Bump for 3.6-28
[LibreOffice.git] / editeng / source / misc / svxacorr.cxx
blob084a79f0346c0bd030932b7cf0c76ec9431b53db
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include <com/sun/star/io/XStream.hpp>
30 #include <com/sun/star/lang/Locale.hpp>
31 #include <tools/urlobj.hxx>
32 #include <i18npool/mslangid.hxx>
33 #include <vcl/svapp.hxx>
34 #include <sot/storinfo.hxx>
35 #include <svl/svstdarr.hxx>
36 #include <svl/fstathelper.hxx>
37 #include <svtools/helpopt.hxx>
38 #include <svl/urihelper.hxx>
39 #include <unotools/charclass.hxx>
40 #include <com/sun/star/i18n/UnicodeType.hdl>
41 #include <unotools/collatorwrapper.hxx>
42 #include <com/sun/star/i18n/CollatorOptions.hpp>
43 #include <com/sun/star/i18n/UnicodeScript.hpp>
44 #include <com/sun/star/i18n/XOrdinalSuffix.hpp>
45 #include <unotools/localedatawrapper.hxx>
46 #include <unotools/transliterationwrapper.hxx>
47 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
48 #include <comphelper/processfactory.hxx>
49 #include <com/sun/star/io/XActiveDataSource.hpp>
50 #include <editeng/editids.hrc>
51 #include <sot/storage.hxx>
52 #include <comphelper/storagehelper.hxx>
53 #include <editeng/udlnitem.hxx>
54 #include <editeng/wghtitem.hxx>
55 #include <editeng/escpitem.hxx>
56 #include <editeng/svxacorr.hxx>
57 #include <editeng/unolingu.hxx>
58 #include "vcl/window.hxx"
59 #include <helpid.hrc>
60 #include <com/sun/star/xml/sax/InputSource.hpp>
61 #include <com/sun/star/xml/sax/XParser.hpp>
62 #include <unotools/streamwrap.hxx>
63 #include <SvXMLAutoCorrectImport.hxx>
64 #include <SvXMLAutoCorrectExport.hxx>
65 #include <ucbhelper/content.hxx>
66 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
67 #include <com/sun/star/ucb/TransferInfo.hpp>
68 #include <com/sun/star/ucb/NameClash.hpp>
69 #include <xmloff/xmltoken.hxx>
70 #include <vcl/help.hxx>
71 #include <rtl/logfile.hxx>
73 #define CHAR_HARDBLANK ((sal_Unicode)0x00A0)
75 using namespace ::com::sun::star::ucb;
76 using namespace ::com::sun::star::uno;
77 using namespace ::com::sun::star;
78 using namespace ::xmloff::token;
79 using namespace ::rtl;
80 using namespace ::utl;
82 static const int C_NONE = 0x00;
83 static const int C_FULL_STOP = 0x01;
84 static const int C_EXCLAMATION_MARK = 0x02;
85 static const int C_QUESTION_MARK = 0x04;
87 static const sal_Char pImplWrdStt_ExcptLstStr[] = "WordExceptList";
88 static const sal_Char pImplCplStt_ExcptLstStr[] = "SentenceExceptList";
89 static const sal_Char pImplAutocorr_ListStr[] = "DocumentList";
90 static const sal_Char pXMLImplWrdStt_ExcptLstStr[] = "WordExceptList.xml";
91 static const sal_Char pXMLImplCplStt_ExcptLstStr[] = "SentenceExceptList.xml";
92 static const sal_Char pXMLImplAutocorr_ListStr[] = "DocumentList.xml";
94 static const sal_Char
95 /* also at these beginnings - Brackets and all kinds of begin characters */
96 sImplSttSkipChars[] = "\"\'([{\x83\x84\x89\x91\x92\x93\x94",
97 /* also at these ends - Brackets and all kinds of begin characters */
98 sImplEndSkipChars[] = "\"\')]}\x83\x84\x89\x91\x92\x93\x94";
100 // These characters are allowed in words: (for FnCptlSttSntnc)
101 static const sal_Char sImplWordChars[] = "-'";
103 void EncryptBlockName_Imp( String& rName );
105 // FileVersions Number for the Substitution-/Exception list separately
106 #define WORDLIST_VERSION_358 1
107 #define EXEPTLIST_VERSION_358 0
109 _SV_IMPL_SORTAR_ALG( SvxAutocorrWordList, SvxAutocorrWordPtr )
110 TYPEINIT0(SvxAutoCorrect)
112 typedef SvxAutoCorrectLanguageLists* SvxAutoCorrectLanguageListsPtr;
114 static inline int IsWordDelim( const sal_Unicode c )
116 return ' ' == c || '\t' == c || 0x0a == c ||
117 0xA0 == c || 0x2011 == c || 0x1 == c;
120 static inline int IsLowerLetter( sal_Int32 nCharType )
122 return CharClass::isLetterType( nCharType ) &&
123 0 == ( ::com::sun::star::i18n::KCharacterType::UPPER & nCharType);
126 static inline int IsUpperLetter( sal_Int32 nCharType )
128 return CharClass::isLetterType( nCharType ) &&
129 0 == ( ::com::sun::star::i18n::KCharacterType::LOWER & nCharType);
132 static sal_Bool lcl_IsSymbolChar( CharClass& rCC, const String& rTxt,
133 xub_StrLen nStt, xub_StrLen nEnd )
135 for( ; nStt < nEnd; ++nStt )
137 if( ::com::sun::star::i18n::UnicodeType::PRIVATE_USE ==
138 rCC.getType( rTxt, nStt ))
139 return sal_True;
141 return sal_False;
144 static sal_Bool lcl_IsInAsciiArr( const sal_Char* pArr, const sal_Unicode c )
146 sal_Bool bRet = sal_False;
147 for( ; *pArr; ++pArr )
148 if( *pArr == c )
150 bRet = sal_True;
151 break;
153 return bRet;
156 SvxAutoCorrDoc::~SvxAutoCorrDoc()
159 // Is called by the functions:
160 // - FnCptlSttWrd
161 // - FnCptlSttSntnc
162 // after the exchange of characters. then the words can maybe be inserted
163 // into the exception list.
164 void SvxAutoCorrDoc::SaveCpltSttWord( sal_uLong, xub_StrLen, const String&,
165 sal_Unicode )
169 LanguageType SvxAutoCorrDoc::GetLanguage( xub_StrLen , sal_Bool ) const
171 return LANGUAGE_SYSTEM;
174 static ::com::sun::star::uno::Reference<
175 ::com::sun::star::lang::XMultiServiceFactory >& GetProcessFact()
177 static ::com::sun::star::uno::Reference<
178 ::com::sun::star::lang::XMultiServiceFactory > xMSF =
179 ::comphelper::getProcessServiceFactory();
180 return xMSF;
183 static sal_uInt16 GetAppLang()
185 return Application::GetSettings().GetLanguage();
187 static LocaleDataWrapper& GetLocaleDataWrapper( sal_uInt16 nLang )
189 static LocaleDataWrapper aLclDtWrp( GetProcessFact(),
190 SvxCreateLocale( GetAppLang() ) );
191 ::com::sun::star::lang::Locale aLcl( SvxCreateLocale( nLang ));
192 const ::com::sun::star::lang::Locale& rLcl = aLclDtWrp.getLoadedLocale();
193 if( aLcl.Language != rLcl.Language ||
194 aLcl.Country != rLcl.Country ||
195 aLcl.Variant != rLcl.Variant )
196 aLclDtWrp.setLocale( aLcl );
197 return aLclDtWrp;
199 static TransliterationWrapper& GetIgnoreTranslWrapper()
201 static int bIsInit = 0;
202 static TransliterationWrapper aWrp( GetProcessFact(),
203 ::com::sun::star::i18n::TransliterationModules_IGNORE_KANA |
204 ::com::sun::star::i18n::TransliterationModules_IGNORE_WIDTH );
205 if( !bIsInit )
207 aWrp.loadModuleIfNeeded( GetAppLang() );
208 bIsInit = 1;
210 return aWrp;
212 static CollatorWrapper& GetCollatorWrapper()
214 static int bIsInit = 0;
215 static CollatorWrapper aCollWrp( GetProcessFact() );
216 if( !bIsInit )
218 aCollWrp.loadDefaultCollator( SvxCreateLocale( GetAppLang() ), 0 );
219 bIsInit = 1;
221 return aCollWrp;
225 void SvxAutocorrWordList::DeleteAndDestroy( sal_uInt16 nP, sal_uInt16 nL )
227 if( nL )
229 OSL_ENSURE( nP < nA && nP + nL <= nA, "ERR_VAR_DEL" );
230 for( sal_uInt16 n=nP; n < nP + nL; n++ )
231 delete *((SvxAutocorrWordPtr*)pData+n);
232 SvPtrarr::Remove( nP, nL );
237 // Keep the list sorted ...
238 sal_Bool SvxAutocorrWordList::Seek_Entry( const SvxAutocorrWordPtr aE, sal_uInt16* pP ) const
240 register sal_uInt16 nO = SvxAutocorrWordList_SAR::Count(),
242 nU = 0;
244 if( nO > 0 )
246 CollatorWrapper& rCmp = ::GetCollatorWrapper();
247 nO--;
249 // quick check of the end of the list
250 if (rCmp.compareString( aE->GetShort(),
251 (*((SvxAutocorrWordPtr*)pData + nO))->GetShort() ) > 0)
253 if( pP ) *pP = nO + 1;
254 return sal_False;
257 // Incredibly crude sort algorithm, should use some partitioning search.
258 while( nU <= nO )
260 nM = nU + ( nO - nU ) / 2;
261 long nCmp = rCmp.compareString( aE->GetShort(),
262 (*((SvxAutocorrWordPtr*)pData + nM))->GetShort() );
263 if( 0 == nCmp )
265 if( pP ) *pP = nM;
266 return sal_True;
268 else if( 0 < nCmp )
269 nU = nM + 1;
270 else if( nM == 0 )
272 if( pP ) *pP = nU;
273 return sal_False;
275 else
276 nO = nM - 1;
279 if( pP ) *pP = nU;
280 return sal_False;
283 static void lcl_ClearTable(boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists>& rLangTable)
285 rLangTable.clear();
288 sal_Bool SvxAutoCorrect::IsAutoCorrectChar( sal_Unicode cChar )
290 return cChar == '\0' || cChar == '\t' || cChar == 0x0a ||
291 cChar == ' ' || cChar == '\'' || cChar == '\"' ||
292 cChar == '*' || cChar == '_' || cChar == '%' ||
293 cChar == '.' || cChar == ',' || cChar == ';' ||
294 cChar == ':' || cChar == '?' || cChar == '!' || cChar == '/';
297 sal_Bool SvxAutoCorrect::NeedsHardspaceAutocorr( sal_Unicode cChar )
299 return cChar == '%' || cChar == ';' || cChar == ':' || cChar == '?' || cChar == '!' ||
300 cChar == '/' /*case for the urls exception*/;
303 long SvxAutoCorrect::GetDefaultFlags()
305 long nRet = Autocorrect
306 | CptlSttSntnc
307 | CptlSttWrd
308 | ChgOrdinalNumber
309 | ChgToEnEmDash
310 | AddNonBrkSpace
311 | ChgWeightUnderl
312 | SetINetAttr
313 | ChgQuotes
314 | SaveWordCplSttLst
315 | SaveWordWrdSttLst
316 | CorrectCapsLock;
317 LanguageType eLang = GetAppLang();
318 switch( eLang )
320 case LANGUAGE_ENGLISH:
321 case LANGUAGE_ENGLISH_US:
322 case LANGUAGE_ENGLISH_UK:
323 case LANGUAGE_ENGLISH_AUS:
324 case LANGUAGE_ENGLISH_CAN:
325 case LANGUAGE_ENGLISH_NZ:
326 case LANGUAGE_ENGLISH_EIRE:
327 case LANGUAGE_ENGLISH_SAFRICA:
328 case LANGUAGE_ENGLISH_JAMAICA:
329 case LANGUAGE_ENGLISH_CARRIBEAN:
330 nRet &= ~(ChgQuotes|ChgSglQuotes);
331 break;
333 return nRet;
337 SvxAutoCorrect::SvxAutoCorrect( const String& rShareAutocorrFile,
338 const String& rUserAutocorrFile )
339 : sShareAutoCorrFile( rShareAutocorrFile ),
340 sUserAutoCorrFile( rUserAutocorrFile ),
341 pLangTable( new boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists> ),
342 pCharClass( 0 ), bRunNext( false ),
343 cStartDQuote( 0 ), cEndDQuote( 0 ), cStartSQuote( 0 ), cEndSQuote( 0 )
345 nFlags = SvxAutoCorrect::GetDefaultFlags();
347 cEmDash = 0x2014;
348 cEnDash = 0x2013;
351 SvxAutoCorrect::SvxAutoCorrect( const SvxAutoCorrect& rCpy )
352 : sShareAutoCorrFile( rCpy.sShareAutoCorrFile ),
353 sUserAutoCorrFile( rCpy.sUserAutoCorrFile ),
355 aSwFlags( rCpy.aSwFlags ),
357 pLangTable( new boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists> ),
358 pCharClass( 0 ), bRunNext( false ),
360 nFlags( rCpy.nFlags & ~(ChgWordLstLoad|CplSttLstLoad|WrdSttLstLoad)),
361 cStartDQuote( rCpy.cStartDQuote ), cEndDQuote( rCpy.cEndDQuote ),
362 cStartSQuote( rCpy.cStartSQuote ), cEndSQuote( rCpy.cEndSQuote ),
363 cEmDash( rCpy.cEmDash ), cEnDash( rCpy.cEnDash )
368 SvxAutoCorrect::~SvxAutoCorrect()
370 lcl_ClearTable(*pLangTable);
371 delete pLangTable;
372 delete pCharClass;
375 void SvxAutoCorrect::_GetCharClass( LanguageType eLang )
377 delete pCharClass;
378 pCharClass = new CharClass( SvxCreateLocale( eLang ));
379 eCharClassLang = eLang;
382 void SvxAutoCorrect::SetAutoCorrFlag( long nFlag, sal_Bool bOn )
384 long nOld = nFlags;
385 nFlags = bOn ? nFlags | nFlag
386 : nFlags & ~nFlag;
388 if( !bOn )
390 if( (nOld & CptlSttSntnc) != (nFlags & CptlSttSntnc) )
391 nFlags &= ~CplSttLstLoad;
392 if( (nOld & CptlSttWrd) != (nFlags & CptlSttWrd) )
393 nFlags &= ~WrdSttLstLoad;
394 if( (nOld & Autocorrect) != (nFlags & Autocorrect) )
395 nFlags &= ~ChgWordLstLoad;
400 // Two capital letters at the beginning of word?
401 sal_Bool SvxAutoCorrect::FnCptlSttWrd( SvxAutoCorrDoc& rDoc, const String& rTxt,
402 xub_StrLen nSttPos, xub_StrLen nEndPos,
403 LanguageType eLang )
405 sal_Bool bRet = sal_False;
406 CharClass& rCC = GetCharClass( eLang );
408 // Delete all non alphanumeric. Test the characters at the beginning/end of
409 // the word ( recognizes: "(min.", "/min.", and so on.)
410 for( ; nSttPos < nEndPos; ++nSttPos )
411 if( rCC.isLetterNumeric( rTxt, nSttPos ))
412 break;
413 for( ; nSttPos < nEndPos; --nEndPos )
414 if( rCC.isLetterNumeric( rTxt, nEndPos - 1 ))
415 break;
417 // Two capital letters at the beginning of word?
418 if( nSttPos+2 < nEndPos &&
419 IsUpperLetter( rCC.getCharacterType( rTxt, nSttPos )) &&
420 IsUpperLetter( rCC.getCharacterType( rTxt, ++nSttPos )) &&
421 // Is the third character a lower case
422 IsLowerLetter( rCC.getCharacterType( rTxt, nSttPos +1 )) &&
423 // Do not replace special attributes
424 0x1 != rTxt.GetChar( nSttPos ) && 0x2 != rTxt.GetChar( nSttPos ))
426 // test if the word is in an exception list
427 String sWord( rTxt.Copy( nSttPos - 1, nEndPos - nSttPos + 1 ));
428 if( !FindInWrdSttExceptList(eLang, sWord) )
430 // Check that word isn't correctly spelled before correcting:
431 ::com::sun::star::uno::Reference<
432 ::com::sun::star::linguistic2::XSpellChecker1 > xSpeller =
433 SvxGetSpellChecker();
434 if( xSpeller->hasLanguage(eLang) )
436 Sequence< ::com::sun::star::beans::PropertyValue > aEmptySeq;
437 if (!xSpeller->spell(sWord, eLang, aEmptySeq).is())
439 return false;
442 sal_Unicode cSave = rTxt.GetChar( nSttPos );
443 String sChar( cSave );
444 sChar = rCC.lowercase( sChar );
445 if( sChar.GetChar(0) != cSave && rDoc.ReplaceRange( nSttPos, 1, sChar ))
447 if( SaveWordWrdSttLst & nFlags )
448 rDoc.SaveCpltSttWord( CptlSttWrd, nSttPos, sWord, cSave );
449 bRet = sal_True;
453 return bRet;
457 sal_Bool SvxAutoCorrect::FnChgOrdinalNumber(
458 SvxAutoCorrDoc& rDoc, const String& rTxt,
459 xub_StrLen nSttPos, xub_StrLen nEndPos,
460 LanguageType eLang )
462 // 1st, 2nd, 3rd, 4 - 0th
463 // 201th or 201st
464 // 12th or 12nd
465 CharClass& rCC = GetCharClass( eLang );
466 sal_Bool bChg = sal_False;
468 for( ; nSttPos < nEndPos; ++nSttPos )
469 if( !lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nSttPos ) ))
470 break;
471 for( ; nSttPos < nEndPos; --nEndPos )
472 if( !lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nEndPos - 1 ) ))
473 break;
476 // Get the last number in the string to check
477 xub_StrLen nNumEnd = nEndPos;
478 bool foundEnd = false;
479 bool validNumber = true;
480 xub_StrLen i = nEndPos;
482 while ( i > nSttPos )
484 i--;
485 bool isDigit = rCC.isDigit( rTxt, i );
486 if ( foundEnd )
487 validNumber |= isDigit;
489 if ( isDigit && !foundEnd )
491 foundEnd = true;
492 nNumEnd = i;
496 if ( foundEnd && validNumber ) {
497 sal_Int32 nNum = rTxt.Copy( nSttPos, nNumEnd - nSttPos + 1 ).ToInt32( );
499 // Check if the characters after that number correspond to the ordinal suffix
500 rtl::OUString sServiceName("com.sun.star.i18n.OrdinalSuffix");
501 uno::Reference< i18n::XOrdinalSuffix > xOrdSuffix(
502 comphelper::createProcessComponent( sServiceName ),
503 uno::UNO_QUERY );
505 if ( xOrdSuffix.is( ) )
507 uno::Sequence< rtl::OUString > aSuffixes = xOrdSuffix->getOrdinalSuffix( nNum, rCC.getLocale( ) );
508 for ( sal_Int32 nSuff = 0; nSuff < aSuffixes.getLength(); nSuff++ )
510 String sSuffix( aSuffixes[ nSuff ] );
511 String sEnd = rTxt.Copy( nNumEnd + 1, nEndPos - nNumEnd - 1 );
513 if ( sSuffix == sEnd )
515 // Check if the ordinal suffix has to be set as super script
516 if ( rCC.isLetter( sSuffix ) )
518 // Do the change
519 SvxEscapementItem aSvxEscapementItem( DFLT_ESC_AUTO_SUPER,
520 DFLT_ESC_PROP, SID_ATTR_CHAR_ESCAPEMENT );
521 rDoc.SetAttr( nNumEnd + 1 , nEndPos,
522 SID_ATTR_CHAR_ESCAPEMENT,
523 aSvxEscapementItem);
530 return bChg;
534 sal_Bool SvxAutoCorrect::FnChgToEnEmDash(
535 SvxAutoCorrDoc& rDoc, const String& rTxt,
536 xub_StrLen nSttPos, xub_StrLen nEndPos,
537 LanguageType eLang )
539 sal_Bool bRet = sal_False;
540 CharClass& rCC = GetCharClass( eLang );
541 if (eLang == LANGUAGE_SYSTEM)
542 eLang = GetAppLang();
543 bool bAlwaysUseEmDash = (cEmDash && (eLang == LANGUAGE_RUSSIAN || eLang == LANGUAGE_UKRAINIAN));
545 // replace " - " or " --" with "enDash"
546 if( cEnDash && 1 < nSttPos && 1 <= nEndPos - nSttPos )
548 sal_Unicode cCh = rTxt.GetChar( nSttPos );
549 if( '-' == cCh )
551 if( ' ' == rTxt.GetChar( nSttPos-1 ) &&
552 '-' == rTxt.GetChar( nSttPos+1 ))
554 xub_StrLen n;
555 for( n = nSttPos+2; n < nEndPos && lcl_IsInAsciiArr(
556 sImplSttSkipChars,(cCh = rTxt.GetChar( n )));
557 ++n )
560 // found: " --[<AnySttChars>][A-z0-9]
561 if( rCC.isLetterNumeric( cCh ) )
563 for( n = nSttPos-1; n && lcl_IsInAsciiArr(
564 sImplEndSkipChars,(cCh = rTxt.GetChar( --n ))); )
567 // found: "[A-z0-9][<AnyEndChars>] --[<AnySttChars>][A-z0-9]
568 if( rCC.isLetterNumeric( cCh ))
570 rDoc.Delete( nSttPos, nSttPos + 2 );
571 rDoc.Insert( nSttPos, bAlwaysUseEmDash ? cEmDash : cEnDash );
572 bRet = sal_True;
577 else if( 3 < nSttPos &&
578 ' ' == rTxt.GetChar( nSttPos-1 ) &&
579 '-' == rTxt.GetChar( nSttPos-2 ))
581 xub_StrLen n, nLen = 1, nTmpPos = nSttPos - 2;
582 if( '-' == ( cCh = rTxt.GetChar( nTmpPos-1 )) )
584 --nTmpPos;
585 ++nLen;
586 cCh = rTxt.GetChar( nTmpPos-1 );
588 if( ' ' == cCh )
590 for( n = nSttPos; n < nEndPos && lcl_IsInAsciiArr(
591 sImplSttSkipChars,(cCh = rTxt.GetChar( n )));
592 ++n )
595 // found: " - [<AnySttChars>][A-z0-9]
596 if( rCC.isLetterNumeric( cCh ) )
598 cCh = ' ';
599 for( n = nTmpPos-1; n && lcl_IsInAsciiArr(
600 sImplEndSkipChars,(cCh = rTxt.GetChar( --n ))); )
602 // found: "[A-z0-9][<AnyEndChars>] - [<AnySttChars>][A-z0-9]
603 if( rCC.isLetterNumeric( cCh ))
605 rDoc.Delete( nTmpPos, nTmpPos + nLen );
606 rDoc.Insert( nTmpPos, bAlwaysUseEmDash ? cEmDash : cEnDash );
607 bRet = sal_True;
614 // Replace [A-z0-9]--[A-z0-9] double dash with "emDash" or "enDash".
615 // Finnish and Hungarian use enDash instead of emDash.
616 bool bEnDash = (eLang == LANGUAGE_HUNGARIAN || eLang == LANGUAGE_FINNISH);
617 if( ((cEmDash && !bEnDash) || (cEnDash && bEnDash)) && 4 <= nEndPos - nSttPos )
619 String sTmp( rTxt.Copy( nSttPos, nEndPos - nSttPos ) );
620 xub_StrLen nFndPos = sTmp.SearchAscii( "--" );
621 if( STRING_NOTFOUND != nFndPos && nFndPos &&
622 nFndPos + 2 < sTmp.Len() &&
623 ( rCC.isLetterNumeric( sTmp, nFndPos - 1 ) ||
624 lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nFndPos - 1 ) )) &&
625 ( rCC.isLetterNumeric( sTmp, nFndPos + 2 ) ||
626 lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nFndPos + 2 ) )))
628 nSttPos = nSttPos + nFndPos;
629 rDoc.Delete( nSttPos, nSttPos + 2 );
630 rDoc.Insert( nSttPos, (bEnDash ? cEnDash : cEmDash) );
631 bRet = sal_True;
634 return bRet;
637 #ifdef _MSC_VER
638 #pragma warning(push)
639 #pragma warning(disable: 4706) // assignment within conditional expression
640 #endif
642 sal_Bool SvxAutoCorrect::FnAddNonBrkSpace(
643 SvxAutoCorrDoc& rDoc, const String& rTxt,
644 xub_StrLen, xub_StrLen nEndPos,
645 LanguageType eLang )
647 bool bRet = false;
649 CharClass& rCC = GetCharClass( eLang );
650 const lang::Locale rLocale = rCC.getLocale( );
652 if ( rLocale.Language == OUString( "fr" ) )
654 bool bFrCA = rLocale.Country == OUString( "CA" );
655 OUString allChars = OUString( ":;?!%" );
656 OUString chars( allChars );
657 if ( bFrCA )
658 chars = OUString( ":" );
660 sal_Unicode cChar = rTxt.GetChar( nEndPos );
661 bool bHasSpace = chars.indexOf( cChar ) != -1;
662 bool bIsSpecial = allChars.indexOf( cChar ) != -1;
663 if ( bIsSpecial )
665 // Get the last word delimiter position
666 xub_StrLen nSttWdPos = nEndPos;
667 bool bWasWordDelim = false;
668 while( nSttWdPos && !(bWasWordDelim = IsWordDelim( rTxt.GetChar( --nSttWdPos ))))
671 if(INetURLObject::CompareProtocolScheme(rTxt.Copy(nSttWdPos + (bWasWordDelim ? 1 : 0), nEndPos - nSttWdPos + 1)) != INET_PROT_NOT_VALID) {
672 return sal_False;
676 // Check the presence of "://" in the word
677 xub_StrLen nStrPos = rTxt.Search( String::CreateFromAscii( "://" ), nSttWdPos + 1 );
678 if ( STRING_NOTFOUND == nStrPos && nEndPos > 0 )
680 // Check the previous char
681 sal_Unicode cPrevChar = rTxt.GetChar( nEndPos - 1 );
682 if ( ( chars.indexOf( cPrevChar ) == -1 ) && cPrevChar != '\t' )
684 // Remove any previous normal space
685 xub_StrLen nPos = nEndPos - 1;
686 while ( cPrevChar == ' ' || cPrevChar == CHAR_HARDBLANK )
688 if ( nPos == 0 ) break;
689 nPos--;
690 cPrevChar = rTxt.GetChar( nPos );
693 nPos++;
694 if ( nEndPos - nPos > 0 )
695 rDoc.Delete( nPos, nEndPos );
697 // Add the non-breaking space at the end pos
698 if ( bHasSpace )
699 rDoc.Insert( nPos, CHAR_HARDBLANK );
700 bRunNext = true;
701 bRet = true;
703 else if ( chars.indexOf( cPrevChar ) != -1 )
704 bRunNext = true;
707 else if ( cChar == '/' && nEndPos > 1 && rTxt.Len() > (nEndPos - 1) )
709 // Remove the hardspace right before to avoid formatting URLs
710 sal_Unicode cPrevChar = rTxt.GetChar( nEndPos - 1 );
711 sal_Unicode cMaybeSpaceChar = rTxt.GetChar( nEndPos - 2 );
712 if ( cPrevChar == ':' && cMaybeSpaceChar == CHAR_HARDBLANK )
714 rDoc.Delete( nEndPos - 2, nEndPos - 1 );
715 bRet = true;
720 return bRet;
723 #ifdef _MSC_VER
724 #pragma warning(pop)
725 #endif
727 sal_Bool SvxAutoCorrect::FnSetINetAttr( SvxAutoCorrDoc& rDoc, const String& rTxt,
728 xub_StrLen nSttPos, xub_StrLen nEndPos,
729 LanguageType eLang )
731 String sURL( URIHelper::FindFirstURLInText( rTxt, nSttPos, nEndPos,
732 GetCharClass( eLang ) ));
733 sal_Bool bRet = 0 != sURL.Len();
734 if( bRet ) // also Attribut setzen:
735 rDoc.SetINetAttr( nSttPos, nEndPos, sURL );
736 return bRet;
740 sal_Bool SvxAutoCorrect::FnChgWeightUnderl( SvxAutoCorrDoc& rDoc, const String& rTxt,
741 xub_StrLen, xub_StrLen nEndPos,
742 LanguageType eLang )
744 // Condition:
745 // at the beginning: _ or * after Space with the folloeing !Space
746 // at the end: _ or * before Space (word delimiter?)
748 sal_Unicode c, cInsChar = rTxt.GetChar( nEndPos ); // underline or bold
749 if( ++nEndPos != rTxt.Len() &&
750 !IsWordDelim( rTxt.GetChar( nEndPos ) ) )
751 return sal_False;
753 --nEndPos;
755 sal_Bool bAlphaNum = sal_False;
756 xub_StrLen nPos = nEndPos, nFndPos = STRING_NOTFOUND;
757 CharClass& rCC = GetCharClass( eLang );
759 while( nPos )
761 switch( c = rTxt.GetChar( --nPos ) )
763 case '_':
764 case '*':
765 if( c == cInsChar )
767 if( bAlphaNum && nPos+1 < nEndPos && ( !nPos ||
768 IsWordDelim( rTxt.GetChar( nPos-1 ))) &&
769 !IsWordDelim( rTxt.GetChar( nPos+1 )))
770 nFndPos = nPos;
771 else
772 // Condition is not satisfied, so cancel
773 nFndPos = STRING_NOTFOUND;
774 nPos = 0;
776 break;
777 default:
778 if( !bAlphaNum )
779 bAlphaNum = rCC.isLetterNumeric( rTxt, nPos );
783 if( STRING_NOTFOUND != nFndPos )
785 // Span the Attribute over the area and delete the Character found at
786 // the end.
787 if( '*' == cInsChar ) // Bold
789 SvxWeightItem aSvxWeightItem( WEIGHT_BOLD, SID_ATTR_CHAR_WEIGHT );
790 rDoc.SetAttr( nFndPos + 1, nEndPos,
791 SID_ATTR_CHAR_WEIGHT,
792 aSvxWeightItem);
794 else // underline
796 SvxUnderlineItem aSvxUnderlineItem( UNDERLINE_SINGLE, SID_ATTR_CHAR_UNDERLINE );
797 rDoc.SetAttr( nFndPos + 1, nEndPos,
798 SID_ATTR_CHAR_UNDERLINE,
799 aSvxUnderlineItem);
801 rDoc.Delete( nEndPos, nEndPos + 1 );
802 rDoc.Delete( nFndPos, nFndPos + 1 );
805 return STRING_NOTFOUND != nFndPos;
809 sal_Bool SvxAutoCorrect::FnCptlSttSntnc( SvxAutoCorrDoc& rDoc,
810 const String& rTxt, sal_Bool bNormalPos,
811 xub_StrLen nSttPos, xub_StrLen nEndPos,
812 LanguageType eLang )
815 if( !rTxt.Len() || nEndPos <= nSttPos )
816 return sal_False;
818 CharClass& rCC = GetCharClass( eLang );
819 String aText( rTxt );
820 const sal_Unicode *pStart = aText.GetBuffer(),
821 *pStr = pStart + nEndPos,
822 *pWordStt = 0,
823 *pDelim = 0;
825 sal_Bool bAtStart = sal_False;
826 do {
827 --pStr;
828 if( rCC.isLetter(
829 aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) )
831 if( !pWordStt )
832 pDelim = pStr+1;
833 pWordStt = pStr;
835 else if( pWordStt &&
836 !rCC.isDigit(
837 aText,
838 sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) )
840 if( lcl_IsInAsciiArr( sImplWordChars, *pStr ) &&
841 pWordStt - 1 == pStr &&
842 // Installation at beginning of paragraph. Replaced < by <= (#i38971#)
843 (long)(pStart + 1) <= (long)pStr &&
844 rCC.isLetter(
845 aText,
846 sal::static_int_cast< xub_StrLen >( pStr-1 - pStart ) ) )
847 pWordStt = --pStr;
848 else
849 break;
851 } while( 0 == ( bAtStart = (pStart == pStr)) );
853 if( !pWordStt ||
854 rCC.isDigit(
855 aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) ||
856 IsUpperLetter(
857 rCC.getCharacterType(
858 aText,
859 sal::static_int_cast< xub_StrLen >( pWordStt - pStart ) ) ) ||
860 INetURLObject::CompareProtocolScheme(rTxt.Copy(pWordStt - pStart, pDelim - pWordStt + 1)) != INET_PROT_NOT_VALID ||
861 0x1 == *pWordStt || 0x2 == *pWordStt )
862 return sal_False; // no character to be replaced, or already ok
864 if( *pDelim && 2 >= pDelim - pWordStt &&
865 lcl_IsInAsciiArr( ".-)>", *pDelim ) )
866 return sal_False;
868 if( !bAtStart ) // Still no beginning of a paragraph?
870 if ( IsWordDelim( *pStr ) )
872 while( 0 == ( bAtStart = (pStart == pStr--) ) && IsWordDelim( *pStr ))
875 // Asian full stop, full width full stop, full width exclamation mark
876 // and full width question marks are treated as word delimiters
877 else if ( 0x3002 != *pStr && 0xFF0E != *pStr && 0xFF01 != *pStr &&
878 0xFF1F != *pStr )
879 return sal_False; // no valid separator -> no replacement
882 if( bAtStart ) // at the beginning of a paragraph?
884 // Check out the previous paragraph, if it exists.
885 // If so, then check to paragraph separator at the end.
886 const String* pPrevPara = rDoc.GetPrevPara( bNormalPos );
887 if( !pPrevPara )
889 // valid separator -> replace
890 String sChar( *pWordStt );
891 sChar = rCC.titlecase( sChar ); //see fdo#56740
892 return sChar != *pWordStt &&
893 rDoc.ReplaceRange( xub_StrLen( pWordStt - pStart ), 1, sChar );
896 aText = *pPrevPara;
897 bAtStart = sal_False;
898 pStart = aText.GetBuffer();
899 pStr = pStart + aText.Len();
901 do { // overwrite all blanks
902 --pStr;
903 if( !IsWordDelim( *pStr ))
904 break;
905 } while( 0 == ( bAtStart = (pStart == pStr)) );
907 if( bAtStart )
908 return sal_False; // no valid separator -> no replacement
911 // Found [ \t]+[A-Z0-9]+ until here. Test now on the paragraph separator.
912 // all three can happen, but not more than once!
913 const sal_Unicode* pExceptStt = 0;
914 if( !bAtStart )
916 sal_Bool bWeiter = sal_True;
917 int nFlag = C_NONE;
918 do {
919 switch( *pStr )
921 // Western and Asian full stop
922 case '.':
923 case 0x3002 :
924 case 0xFF0E :
926 if( nFlag & C_FULL_STOP )
927 return sal_False; // no valid separator -> no replacement
928 nFlag |= C_FULL_STOP;
929 pExceptStt = pStr;
931 break;
932 case '!':
933 case 0xFF01 :
935 if( nFlag & C_EXCLAMATION_MARK )
936 return sal_False; // no valid separator -> no replacement
937 nFlag |= C_EXCLAMATION_MARK;
939 break;
940 case '?':
941 case 0xFF1F :
943 if( nFlag & C_QUESTION_MARK)
944 return sal_False; // no valid separator -> no replacement
945 nFlag |= C_QUESTION_MARK;
947 break;
948 default:
949 if( !nFlag )
950 return sal_False; // no valid separator -> no replacement
951 else
952 bWeiter = sal_False;
953 break;
956 if( bWeiter && pStr-- == pStart )
958 return sal_False; // no valid separator -> no replacement
960 } while( bWeiter );
961 if( C_FULL_STOP != nFlag )
962 pExceptStt = 0;
965 if( 2 > ( pStr - pStart ) )
966 return sal_False;
968 if( !rCC.isLetterNumeric(
969 aText, sal::static_int_cast< xub_StrLen >( pStr-- - pStart ) ) )
971 sal_Bool bValid = sal_False, bAlphaFnd = sal_False;
972 const sal_Unicode* pTmpStr = pStr;
973 while( !bValid )
975 if( rCC.isDigit(
976 aText,
977 sal::static_int_cast< xub_StrLen >( pTmpStr - pStart ) ) )
979 bValid = sal_True;
980 pStr = pTmpStr - 1;
982 else if( rCC.isLetter(
983 aText,
984 sal::static_int_cast< xub_StrLen >(
985 pTmpStr - pStart ) ) )
987 if( bAlphaFnd )
989 bValid = sal_True;
990 pStr = pTmpStr;
992 else
993 bAlphaFnd = sal_True;
995 else if( bAlphaFnd || IsWordDelim( *pTmpStr ) )
996 break;
998 if( pTmpStr == pStart )
999 break;
1001 --pTmpStr;
1004 if( !bValid )
1005 return sal_False; // no valid separator -> no replacement
1008 sal_Bool bNumericOnly = '0' <= *(pStr+1) && *(pStr+1) <= '9';
1010 // Search for the beginning of the word
1011 while( !IsWordDelim( *pStr ))
1013 if( bNumericOnly &&
1014 rCC.isLetter(
1015 aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) )
1016 bNumericOnly = sal_False;
1018 if( pStart == pStr )
1019 break;
1021 --pStr;
1024 if( bNumericOnly ) // consists of only numbers, then not
1025 return sal_False;
1027 if( IsWordDelim( *pStr ))
1028 ++pStr;
1030 String sWord;
1032 // check on the basis of the exception list
1033 if( pExceptStt )
1035 sWord = String(
1036 pStr, sal::static_int_cast< xub_StrLen >( pExceptStt - pStr + 1 ) );
1037 if( FindInCplSttExceptList(eLang, sWord) )
1038 return sal_False;
1040 // Delete all non alphanumeric. Test the characters at the
1041 // beginning/end of the word ( recognizes: "(min.", "/min.", and so on.)
1042 String sTmp( sWord );
1043 while( sTmp.Len() &&
1044 !rCC.isLetterNumeric( sTmp, 0 ) )
1045 sTmp.Erase( 0, 1 );
1047 // Remove all non alphanumeric characters towards the end up until
1048 // the last one.
1049 xub_StrLen nLen = sTmp.Len();
1050 while( nLen && !rCC.isLetterNumeric( sTmp, nLen-1 ) )
1051 --nLen;
1052 if( nLen + 1 < sTmp.Len() )
1053 sTmp.Erase( nLen + 1 );
1055 if( sTmp.Len() && sTmp.Len() != sWord.Len() &&
1056 FindInCplSttExceptList(eLang, sTmp))
1057 return sal_False;
1059 if(FindInCplSttExceptList(eLang, sWord, sal_True))
1060 return sal_False;
1063 // Ok, then replace
1064 sal_Unicode cSave = *pWordStt;
1065 nSttPos = sal::static_int_cast< xub_StrLen >( pWordStt - rTxt.GetBuffer() );
1066 String sChar( cSave );
1067 sChar = rCC.titlecase( sChar ); //see fdo#56740
1068 sal_Bool bRet = sChar.GetChar(0) != cSave && rDoc.ReplaceRange( nSttPos, 1, sChar );
1070 // Parahaps someone wants to have the word
1071 if( bRet && SaveWordCplSttLst & nFlags )
1072 rDoc.SaveCpltSttWord( CptlSttSntnc, nSttPos, sWord, cSave );
1074 return bRet;
1077 bool SvxAutoCorrect::FnCorrectCapsLock( SvxAutoCorrDoc& rDoc, const String& rTxt,
1078 xub_StrLen nSttPos, xub_StrLen nEndPos,
1079 LanguageType eLang )
1081 if (nEndPos - nSttPos < 2)
1082 // string must be at least 2-character long.
1083 return false;
1085 CharClass& rCC = GetCharClass( eLang );
1087 // Check the first 2 letters.
1088 if ( !IsLowerLetter(rCC.getCharacterType(rTxt, nSttPos)) )
1089 return false;
1091 if ( !IsUpperLetter(rCC.getCharacterType(rTxt, nSttPos+1)) )
1092 return false;
1094 String aConverted;
1095 aConverted.Append( rCC.uppercase(rtl::OUString(rTxt.GetChar(nSttPos))) );
1096 aConverted.Append( rCC.lowercase(rtl::OUString(rTxt.GetChar(nSttPos+1))) );
1098 for (xub_StrLen i = nSttPos+2; i < nEndPos; ++i)
1100 if ( IsLowerLetter(rCC.getCharacterType(rTxt, i)) )
1101 // A lowercase letter disqualifies the whole text.
1102 return false;
1104 if ( IsUpperLetter(rCC.getCharacterType(rTxt, i)) )
1105 // Another uppercase letter. Convert it.
1106 aConverted.Append( rCC.lowercase(String(rTxt.GetChar(i))) );
1107 else
1108 // This is not an alphabetic letter. Leave it as-is.
1109 aConverted.Append(rTxt.GetChar(i));
1112 // Replace the word.
1113 rDoc.Delete(nSttPos, nEndPos);
1114 rDoc.Insert(nSttPos, aConverted);
1116 return true;
1120 sal_Unicode SvxAutoCorrect::GetQuote( sal_Unicode cInsChar, sal_Bool bSttQuote,
1121 LanguageType eLang ) const
1123 sal_Unicode cRet = bSttQuote ? ( '\"' == cInsChar
1124 ? GetStartDoubleQuote()
1125 : GetStartSingleQuote() )
1126 : ( '\"' == cInsChar
1127 ? GetEndDoubleQuote()
1128 : GetEndSingleQuote() );
1129 if( !cRet )
1131 // then through the Language find the right character
1132 if( LANGUAGE_NONE == eLang )
1133 cRet = cInsChar;
1134 else
1136 LocaleDataWrapper& rLcl = GetLocaleDataWrapper( eLang );
1137 String sRet( bSttQuote
1138 ? ( '\"' == cInsChar
1139 ? rLcl.getDoubleQuotationMarkStart()
1140 : rLcl.getQuotationMarkStart() )
1141 : ( '\"' == cInsChar
1142 ? rLcl.getDoubleQuotationMarkEnd()
1143 : rLcl.getQuotationMarkEnd() ));
1144 cRet = sRet.Len() ? sRet.GetChar( 0 ) : cInsChar;
1147 return cRet;
1150 void SvxAutoCorrect::InsertQuote( SvxAutoCorrDoc& rDoc, xub_StrLen nInsPos,
1151 sal_Unicode cInsChar, sal_Bool bSttQuote,
1152 sal_Bool bIns )
1154 LanguageType eLang = rDoc.GetLanguage( nInsPos, sal_False );
1155 sal_Unicode cRet = GetQuote( cInsChar, bSttQuote, eLang );
1157 String sChg( cInsChar );
1158 if( bIns )
1159 rDoc.Insert( nInsPos, sChg );
1160 else
1161 rDoc.Replace( nInsPos, sChg );
1163 sChg = cRet;
1165 if( '\"' == cInsChar )
1167 if( LANGUAGE_SYSTEM == eLang )
1168 eLang = GetAppLang();
1169 switch( eLang )
1171 case LANGUAGE_FRENCH:
1172 case LANGUAGE_FRENCH_BELGIAN:
1173 case LANGUAGE_FRENCH_CANADIAN:
1174 case LANGUAGE_FRENCH_SWISS:
1175 case LANGUAGE_FRENCH_LUXEMBOURG:
1177 String s( static_cast< sal_Unicode >(0xA0) );
1178 // UNICODE code for no break space
1179 if( rDoc.Insert( bSttQuote ? nInsPos+1 : nInsPos, s ))
1181 if( !bSttQuote )
1182 ++nInsPos;
1185 break;
1189 rDoc.Replace( nInsPos, sChg );
1192 String SvxAutoCorrect::GetQuote( SvxAutoCorrDoc& rDoc, xub_StrLen nInsPos,
1193 sal_Unicode cInsChar, sal_Bool bSttQuote )
1195 LanguageType eLang = rDoc.GetLanguage( nInsPos, sal_False );
1196 sal_Unicode cRet = GetQuote( cInsChar, bSttQuote, eLang );
1198 String sRet( cRet );
1200 if( '\"' == cInsChar )
1202 if( LANGUAGE_SYSTEM == eLang )
1203 eLang = GetAppLang();
1204 switch( eLang )
1206 case LANGUAGE_FRENCH:
1207 case LANGUAGE_FRENCH_BELGIAN:
1208 case LANGUAGE_FRENCH_CANADIAN:
1209 case LANGUAGE_FRENCH_SWISS:
1210 case LANGUAGE_FRENCH_LUXEMBOURG:
1211 if( bSttQuote )
1212 sRet += ' ';
1213 else
1214 sRet.Insert( ' ', 0 );
1215 break;
1218 return sRet;
1221 sal_uLong SvxAutoCorrect::AutoCorrect( SvxAutoCorrDoc& rDoc, const String& rTxt,
1222 xub_StrLen nInsPos, sal_Unicode cChar,
1223 sal_Bool bInsert, Window* pFrameWin )
1225 sal_uLong nRet = 0;
1226 bool bIsNextRun = bRunNext;
1227 bRunNext = false; // if it was set, then it has to be turned off
1229 do{ // only for middle check loop !!
1230 if( cChar )
1232 // Prevent double space
1233 if( nInsPos && ' ' == cChar &&
1234 IsAutoCorrFlag( IgnoreDoubleSpace ) &&
1235 ' ' == rTxt.GetChar( nInsPos - 1 ) )
1237 nRet = IgnoreDoubleSpace;
1238 break;
1241 sal_Bool bSingle = '\'' == cChar;
1242 sal_Bool bIsReplaceQuote =
1243 (IsAutoCorrFlag( ChgQuotes ) && ('\"' == cChar )) ||
1244 (IsAutoCorrFlag( ChgSglQuotes ) && bSingle );
1245 if( bIsReplaceQuote )
1247 sal_Unicode cPrev;
1248 sal_Bool bSttQuote = !nInsPos ||
1249 IsWordDelim( ( cPrev = rTxt.GetChar( nInsPos-1 ))) ||
1250 lcl_IsInAsciiArr( "([{", cPrev ) ||
1251 ( cEmDash && cEmDash == cPrev ) ||
1252 ( cEnDash && cEnDash == cPrev );
1254 InsertQuote( rDoc, nInsPos, cChar, bSttQuote, bInsert );
1255 nRet = bSingle ? ChgSglQuotes : ChgQuotes;
1256 break;
1259 if( bInsert )
1260 rDoc.Insert( nInsPos, cChar );
1261 else
1262 rDoc.Replace( nInsPos, cChar );
1264 // Hardspaces autocorrection
1265 if ( IsAutoCorrFlag( AddNonBrkSpace ) )
1267 if ( NeedsHardspaceAutocorr( cChar ) &&
1268 FnAddNonBrkSpace( rDoc, rTxt, 0, nInsPos, rDoc.GetLanguage( nInsPos, sal_False ) ) )
1270 nRet = AddNonBrkSpace;
1272 else if ( bIsNextRun && !IsAutoCorrectChar( cChar ) )
1274 // Remove the NBSP if it wasn't an autocorrection
1275 if ( nInsPos != 0 && NeedsHardspaceAutocorr( rTxt.GetChar( nInsPos - 1 ) ) &&
1276 cChar != ' ' && cChar != '\t' && cChar != CHAR_HARDBLANK )
1278 // Look for the last HARD_SPACE
1279 xub_StrLen nPos = nInsPos - 1;
1280 bool bContinue = true;
1281 while ( bContinue )
1283 const sal_Unicode cTmpChar = rTxt.GetChar( nPos );
1284 if ( cTmpChar == CHAR_HARDBLANK )
1286 rDoc.Delete( nPos, nPos + 1 );
1287 nRet = AddNonBrkSpace;
1288 bContinue = false;
1290 else if ( !NeedsHardspaceAutocorr( cTmpChar ) || nPos == 0 )
1291 bContinue = false;
1292 nPos--;
1299 if( !nInsPos )
1300 break;
1302 xub_StrLen nPos = nInsPos - 1;
1304 if( IsWordDelim( rTxt.GetChar( nPos )))
1305 break;
1307 // Set bold or underline automatically?
1308 if( '*' == cChar || '_' == cChar )
1310 if( IsAutoCorrFlag( ChgWeightUnderl ) &&
1311 FnChgWeightUnderl( rDoc, rTxt, 0, nPos+1 ) )
1312 nRet = ChgWeightUnderl;
1313 break;
1316 while( nPos && !IsWordDelim( rTxt.GetChar( --nPos )))
1319 // Found a Paragraph-start or a Blank, search for the word shortcut in
1320 // auto.
1321 xub_StrLen nCapLttrPos = nPos+1; // on the 1st Character
1322 if( !nPos && !IsWordDelim( rTxt.GetChar( 0 )))
1323 --nCapLttrPos; // Absatz Anfang und kein Blank !
1325 LanguageType eLang = rDoc.GetLanguage( nCapLttrPos, sal_False );
1326 if( LANGUAGE_SYSTEM == eLang )
1327 eLang = MsLangId::getSystemLanguage();
1328 CharClass& rCC = GetCharClass( eLang );
1330 // no symbol characters
1331 if( lcl_IsSymbolChar( rCC, rTxt, nCapLttrPos, nInsPos ))
1332 break;
1334 if( IsAutoCorrFlag( Autocorrect ) )
1336 const String* pPara = 0;
1337 const String** ppPara = IsAutoCorrFlag(CptlSttSntnc) ? &pPara : 0;
1339 sal_Bool bChgWord = rDoc.ChgAutoCorrWord( nCapLttrPos, nInsPos,
1340 *this, ppPara );
1341 if( !bChgWord )
1343 xub_StrLen nCapLttrPos1 = nCapLttrPos, nInsPos1 = nInsPos;
1344 while( nCapLttrPos1 < nInsPos &&
1345 lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nCapLttrPos1 ) )
1347 ++nCapLttrPos1;
1348 while( nCapLttrPos1 < nInsPos1 && nInsPos1 &&
1349 lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nInsPos1-1 ) )
1351 --nInsPos1;
1353 if( (nCapLttrPos1 != nCapLttrPos || nInsPos1 != nInsPos ) &&
1354 nCapLttrPos1 < nInsPos1 &&
1355 rDoc.ChgAutoCorrWord( nCapLttrPos1, nInsPos1, *this, ppPara ))
1357 bChgWord = sal_True;
1358 nCapLttrPos = nCapLttrPos1;
1362 if( bChgWord )
1364 nRet = Autocorrect;
1365 if( pPara )
1367 xub_StrLen nEnd = nCapLttrPos;
1368 while( nEnd < pPara->Len() &&
1369 !IsWordDelim( pPara->GetChar( nEnd )))
1370 ++nEnd;
1372 // Capital letter at beginning of paragraph?
1373 if( IsAutoCorrFlag( CptlSttSntnc ) &&
1374 FnCptlSttSntnc( rDoc, *pPara, sal_False,
1375 nCapLttrPos, nEnd, eLang ) )
1376 nRet |= CptlSttSntnc;
1378 if( IsAutoCorrFlag( ChgToEnEmDash ) &&
1379 FnChgToEnEmDash( rDoc, rTxt, nCapLttrPos, nEnd, eLang ) )
1380 nRet |= ChgToEnEmDash;
1382 break;
1386 if( ( IsAutoCorrFlag( nRet = ChgOrdinalNumber ) &&
1387 FnChgOrdinalNumber( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) ||
1388 ( IsAutoCorrFlag( nRet = SetINetAttr ) &&
1389 ( ' ' == cChar || '\t' == cChar || 0x0a == cChar || !cChar ) &&
1390 FnSetINetAttr( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) )
1392 else
1394 bool bLockKeyOn = pFrameWin && (pFrameWin->GetIndicatorState() & INDICATOR_CAPSLOCK);
1396 nRet = 0;
1397 if ( bLockKeyOn && IsAutoCorrFlag( CorrectCapsLock ) &&
1398 FnCorrectCapsLock( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) )
1400 // Correct accidental use of cAPS LOCK key (do this only when
1401 // the caps or shift lock key is pressed). Turn off the caps
1402 // lock afterwords.
1403 nRet |= CorrectCapsLock;
1404 pFrameWin->SimulateKeyPress( KEY_CAPSLOCK );
1407 // Capital letter at beginning of paragraph ?
1408 if( IsAutoCorrFlag( CptlSttSntnc ) &&
1409 FnCptlSttSntnc( rDoc, rTxt, sal_True, nCapLttrPos, nInsPos, eLang ) )
1410 nRet |= CptlSttSntnc;
1412 // Two capital letters at beginning of word ??
1413 if( IsAutoCorrFlag( CptlSttWrd ) &&
1414 FnCptlSttWrd( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) )
1415 nRet |= CptlSttWrd;
1417 if( IsAutoCorrFlag( ChgToEnEmDash ) &&
1418 FnChgToEnEmDash( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) )
1419 nRet |= ChgToEnEmDash;
1422 } while( sal_False );
1424 if( nRet )
1426 const char* aHelpIds[] =
1428 HID_AUTOCORR_HELP_WORD,
1429 HID_AUTOCORR_HELP_SENT,
1430 HID_AUTOCORR_HELP_SENTWORD,
1431 HID_AUTOCORR_HELP_ACORWORD,
1433 HID_AUTOCORR_HELP_ACORSENTWORD,
1435 HID_AUTOCORR_HELP_CHGTOENEMDASH,
1436 HID_AUTOCORR_HELP_WORDENEMDASH,
1437 HID_AUTOCORR_HELP_SENTENEMDASH,
1438 HID_AUTOCORR_HELP_SENTWORDENEMDASH,
1439 HID_AUTOCORR_HELP_ACORWORDENEMDASH,
1441 HID_AUTOCORR_HELP_ACORSENTWORDENEMDASH,
1443 HID_AUTOCORR_HELP_CHGQUOTES,
1444 HID_AUTOCORR_HELP_CHGSGLQUOTES,
1445 HID_AUTOCORR_HELP_SETINETATTR,
1446 HID_AUTOCORR_HELP_INGNOREDOUBLESPACE,
1447 HID_AUTOCORR_HELP_CHGWEIGHTUNDERL,
1448 HID_AUTOCORR_HELP_CHGFRACTIONSYMBOL,
1449 HID_AUTOCORR_HELP_CHGORDINALNUMBER
1452 sal_uLong nHelpId = 0;
1453 if( nRet & ( Autocorrect|CptlSttSntnc|CptlSttWrd|ChgToEnEmDash ) )
1455 // from 0 - 15
1456 if( nRet & ChgToEnEmDash )
1457 nHelpId += 8;
1458 if( nRet & Autocorrect )
1459 nHelpId += 4;
1460 if( nRet & CptlSttSntnc )
1461 nHelpId += 2;
1462 if( nRet & CptlSttWrd )
1463 nHelpId += 1;
1465 else
1467 if( nRet & ChgQuotes) nHelpId = 16;
1468 else if( nRet & ChgSglQuotes) nHelpId = 17;
1469 else if( nRet & SetINetAttr) nHelpId = 18;
1470 else if( nRet & IgnoreDoubleSpace) nHelpId = 19;
1471 else if( nRet & ChgWeightUnderl) nHelpId = 20;
1472 else if( nRet & AddNonBrkSpace) nHelpId = 21;
1473 else if( nRet & ChgOrdinalNumber) nHelpId = 22;
1476 if( nHelpId )
1478 nHelpId -= 1;
1479 Application::GetHelp()->OpenHelpAgent( aHelpIds[nHelpId] );
1484 return nRet;
1487 SvxAutoCorrectLanguageLists& SvxAutoCorrect::_GetLanguageList(
1488 LanguageType eLang )
1490 if(pLangTable->find(eLang) == pLangTable->end())
1491 CreateLanguageFile(eLang, sal_True);
1492 return *(pLangTable->find(eLang)->second);
1495 void SvxAutoCorrect::SaveCplSttExceptList( LanguageType eLang )
1497 boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(eLang);
1498 if(nTmpVal != pLangTable->end() && nTmpVal->second)
1499 nTmpVal->second->SaveCplSttExceptList();
1500 #ifdef DBG_UTIL
1501 else
1503 OSL_FAIL("Save an empty list? ");
1505 #endif
1508 void SvxAutoCorrect::SaveWrdSttExceptList(LanguageType eLang)
1510 boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(eLang);
1511 if(nTmpVal != pLangTable->end() && nTmpVal->second)
1512 nTmpVal->second->SaveWrdSttExceptList();
1513 #ifdef DBG_UTIL
1514 else
1516 OSL_FAIL("Save an empty list? ");
1518 #endif
1521 // Adds a single word. The list will immediately be written to the file!
1522 sal_Bool SvxAutoCorrect::AddCplSttException( const String& rNew,
1523 LanguageType eLang )
1525 SvxAutoCorrectLanguageLists* pLists = 0;
1526 // either the right language is present or it will be this in the general list
1527 boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(eLang);
1528 if(nTmpVal != pLangTable->end())
1529 pLists = nTmpVal->second;
1530 else
1532 nTmpVal = pLangTable->find(LANGUAGE_DONTKNOW);
1533 if(nTmpVal != pLangTable->end())
1534 pLists = nTmpVal->second;
1535 else if(CreateLanguageFile(LANGUAGE_DONTKNOW, sal_True))
1536 pLists = pLangTable->find(LANGUAGE_DONTKNOW)->second;
1538 OSL_ENSURE(pLists, "No auto correction data");
1539 return pLists->AddToCplSttExceptList(rNew);
1542 // Adds a single word. The list will immediately be written to the file!
1543 sal_Bool SvxAutoCorrect::AddWrtSttException( const String& rNew,
1544 LanguageType eLang )
1546 SvxAutoCorrectLanguageLists* pLists = 0;
1547 //either the right language is present or it is set in the general list
1548 boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(eLang);
1549 if(nTmpVal != pLangTable->end())
1550 pLists = nTmpVal->second;
1551 else
1553 nTmpVal = pLangTable->find(LANGUAGE_DONTKNOW);
1554 if(nTmpVal != pLangTable->end())
1555 pLists = nTmpVal->second;
1556 else if(CreateLanguageFile(LANGUAGE_DONTKNOW, sal_True))
1557 pLists = pLangTable->find(LANGUAGE_DONTKNOW)->second;
1559 OSL_ENSURE(pLists, "keine Autokorrekturdatei");
1560 return pLists->AddToWrdSttExceptList(rNew);
1563 sal_Bool SvxAutoCorrect::GetPrevAutoCorrWord( SvxAutoCorrDoc& rDoc,
1564 const String& rTxt, xub_StrLen nPos,
1565 String& rWord ) const
1567 if( !nPos )
1568 return sal_False;
1570 xub_StrLen nEnde = nPos;
1572 // it must be followed by a blank or tab!
1573 if( ( nPos < rTxt.Len() &&
1574 !IsWordDelim( rTxt.GetChar( nPos ))) ||
1575 IsWordDelim( rTxt.GetChar( --nPos )))
1576 return sal_False;
1578 while( nPos && !IsWordDelim( rTxt.GetChar( --nPos )))
1581 // Found a Paragraph-start or a Blank, search for the word shortcut in
1582 // auto.
1583 xub_StrLen nCapLttrPos = nPos+1; // on the 1st Character
1584 if( !nPos && !IsWordDelim( rTxt.GetChar( 0 )))
1585 --nCapLttrPos; // Beginning of pargraph and no Blank!
1587 while( lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nCapLttrPos )) )
1588 if( ++nCapLttrPos >= nEnde )
1589 return sal_False;
1591 if( 3 > nEnde - nCapLttrPos )
1592 return sal_False;
1594 LanguageType eLang = rDoc.GetLanguage( nCapLttrPos, sal_False );
1595 if( LANGUAGE_SYSTEM == eLang )
1596 eLang = MsLangId::getSystemLanguage();
1598 SvxAutoCorrect* pThis = (SvxAutoCorrect*)this;
1599 CharClass& rCC = pThis->GetCharClass( eLang );
1601 if( lcl_IsSymbolChar( rCC, rTxt, nCapLttrPos, nEnde ))
1602 return sal_False;
1604 rWord = rTxt.Copy( nCapLttrPos, nEnde - nCapLttrPos );
1605 return sal_True;
1608 sal_Bool SvxAutoCorrect::CreateLanguageFile( LanguageType eLang, sal_Bool bNewFile )
1610 OSL_ENSURE(pLangTable->find(eLang) == pLangTable->end(), "Language already exists ");
1612 String sUserDirFile( GetAutoCorrFileName( eLang, sal_True, sal_False )),
1613 sShareDirFile( sUserDirFile );
1614 SvxAutoCorrectLanguageListsPtr pLists = 0;
1616 Time nMinTime( 0, 2 ), nAktTime( Time::SYSTEM ), nLastCheckTime( Time::EMPTY );
1618 std::map<LanguageType, long>::iterator nFndPos = aLastFileTable.find(eLang);
1619 if(nFndPos != aLastFileTable.end() &&
1620 (nLastCheckTime.SetTime(nFndPos->second), nLastCheckTime < nAktTime) &&
1621 nAktTime - nLastCheckTime < nMinTime)
1623 // no need to test the file, because the last check is not older then
1624 // 2 minutes.
1625 if( bNewFile )
1627 sShareDirFile = sUserDirFile;
1628 pLists = new SvxAutoCorrectLanguageLists( *this, sShareDirFile,
1629 sUserDirFile, eLang );
1630 pLangTable->insert(eLang, pLists);
1631 aLastFileTable.erase(nFndPos);
1634 else if( ( FStatHelper::IsDocument( sUserDirFile ) ||
1635 FStatHelper::IsDocument( sShareDirFile =
1636 GetAutoCorrFileName( eLang, sal_False, sal_False ) ) ) ||
1637 ( sShareDirFile = sUserDirFile, bNewFile ))
1639 pLists = new SvxAutoCorrectLanguageLists( *this, sShareDirFile,
1640 sUserDirFile, eLang );
1641 pLangTable->insert(eLang, pLists);
1642 if (nFndPos != aLastFileTable.end())
1643 aLastFileTable.erase(nFndPos);
1645 else if( !bNewFile )
1647 aLastFileTable[eLang] = nAktTime.GetTime();
1649 return pLists != 0;
1652 sal_Bool SvxAutoCorrect::PutText( const String& rShort, const String& rLong,
1653 LanguageType eLang )
1655 boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(eLang);
1656 if(nTmpVal != pLangTable->end())
1657 return nTmpVal->second->PutText(rShort, rLong);
1658 if(CreateLanguageFile(eLang))
1659 return pLangTable->find(eLang)->second->PutText(rShort, rLong);
1660 return sal_False;
1663 // - Delete an entry
1664 sal_Bool SvxAutoCorrect::DeleteText( const String& rShort, LanguageType eLang )
1666 boost::ptr_map<LanguageType, SvxAutoCorrectLanguageLists>::iterator nTmpVal = pLangTable->find(eLang);
1667 if(nTmpVal != pLangTable->end())
1668 return nTmpVal->second->DeleteText(rShort);
1669 return sal_False;
1672 // - return the replacement text (only for SWG-Format, all other
1673 // can be taken from the word list!)
1674 sal_Bool SvxAutoCorrect::GetLongText( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >&, const String&, const String& , String& )
1676 return sal_False;
1679 // Text with attribution (only the SWG - SWG format!)
1680 sal_Bool SvxAutoCorrect::PutText( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >&, const String&, const String&, SfxObjectShell&,
1681 String& )
1683 return sal_False;
1686 void EncryptBlockName_Imp( String& rName )
1688 xub_StrLen nLen, nPos = 1;
1689 rName.Insert( '#', 0 );
1690 sal_Unicode* pName = rName.GetBufferAccess();
1691 for ( nLen = rName.Len(), ++pName; nPos < nLen; ++nPos, ++pName )
1693 if( lcl_IsInAsciiArr( "!/:.\\", *pName ))
1694 *pName &= 0x0f;
1698 /* This code is copied from SwXMLTextBlocks::GeneratePackageName */
1699 static void GeneratePackageName ( const String& rShort, String& rPackageName )
1701 rPackageName = rShort;
1702 xub_StrLen nPos = 0;
1703 sal_Unicode pDelims[] = { '!', '/', ':', '.', '\\', 0 };
1704 rtl::OString sByte(rtl::OUStringToOString(rPackageName, RTL_TEXTENCODING_UTF7));
1705 rPackageName = rtl::OStringToOUString(sByte, RTL_TEXTENCODING_ASCII_US);
1706 while( STRING_NOTFOUND != ( nPos = rPackageName.SearchChar( pDelims, nPos )))
1708 rPackageName.SetChar( nPos, '_' );
1709 ++nPos;
1713 static const SvxAutocorrWord* lcl_SearchWordsInList(
1714 SvxAutoCorrectLanguageListsPtr pList, const String& rTxt,
1715 xub_StrLen& rStt, xub_StrLen nEndPos, SvxAutoCorrDoc& )
1717 const SvxAutocorrWordList* pAutoCorrWordList = pList->GetAutocorrWordList();
1718 TransliterationWrapper& rCmp = GetIgnoreTranslWrapper();
1719 for( xub_StrLen nPos = 0; nPos < pAutoCorrWordList->Count(); ++nPos )
1721 const SvxAutocorrWord* pFnd = (*pAutoCorrWordList)[ nPos ];
1722 const String& rChk = pFnd->GetShort();
1723 if( nEndPos >= rChk.Len() )
1725 xub_StrLen nCalcStt = nEndPos - rChk.Len();
1726 if( ( !nCalcStt || nCalcStt == rStt ||
1727 ( nCalcStt < rStt &&
1728 IsWordDelim( rTxt.GetChar(nCalcStt - 1 ) ))) )
1730 String sWord( rTxt.GetBuffer() + nCalcStt, rChk.Len() );
1731 if( rCmp.isEqual( rChk, sWord ))
1733 rStt = nCalcStt;
1734 return pFnd;
1739 return 0;
1743 // the search or the words in the substitution table
1744 const SvxAutocorrWord* SvxAutoCorrect::SearchWordsInList(
1745 const String& rTxt, xub_StrLen& rStt, xub_StrLen nEndPos,
1746 SvxAutoCorrDoc& rDoc, LanguageType& rLang )
1748 LanguageType eLang = rLang;
1749 const SvxAutocorrWord* pRet = 0;
1750 if( LANGUAGE_SYSTEM == eLang )
1751 eLang = MsLangId::getSystemLanguage();
1753 // First search for eLang, then US-English -> English
1754 // and last in LANGUAGE_DONTKNOW
1755 if(pLangTable->find(eLang) != pLangTable->end() || CreateLanguageFile(eLang, sal_False))
1757 //the language is available - so bring it on
1758 SvxAutoCorrectLanguageLists* pList = pLangTable->find(eLang)->second;
1759 pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos, rDoc );
1760 if( pRet )
1762 rLang = eLang;
1763 return pRet;
1767 // If it still could not be found here, then keep on searching
1769 LanguageType nTmpKey1 = eLang & 0x7ff, // the main language in many cases DE
1770 nTmpKey2 = eLang & 0x3ff; // otherwise for example EN
1771 if(nTmpKey1 != eLang && (pLangTable->find(nTmpKey1) != pLangTable->end() || CreateLanguageFile(nTmpKey1, sal_False)))
1773 //the language is available - so bring it on
1774 SvxAutoCorrectLanguageLists* pList = pLangTable->find(nTmpKey1)->second;
1775 pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos, rDoc);
1776 if( pRet )
1778 rLang = nTmpKey1;
1779 return pRet;
1783 if(nTmpKey2 != eLang && (pLangTable->find(nTmpKey2) != pLangTable->end() || CreateLanguageFile(nTmpKey2, sal_False)))
1785 //the language is available - so bring it on
1786 SvxAutoCorrectLanguageLists* pList = pLangTable->find(nTmpKey2)->second;
1787 pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos, rDoc);
1788 if( pRet )
1790 rLang = nTmpKey2;
1791 return pRet;
1795 if(pLangTable->find(LANGUAGE_DONTKNOW) != pLangTable->end() || CreateLanguageFile(LANGUAGE_DONTKNOW, sal_False))
1797 //the language is available - so bring it on
1798 SvxAutoCorrectLanguageLists* pList = pLangTable->find(LANGUAGE_DONTKNOW)->second;
1799 pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos, rDoc);
1800 if( pRet )
1802 rLang = LANGUAGE_DONTKNOW;
1803 return pRet;
1806 return 0;
1809 sal_Bool SvxAutoCorrect::FindInWrdSttExceptList( LanguageType eLang,
1810 const String& sWord )
1812 // First search for eLang, then US-English -> English
1813 // and last in LANGUAGE_DONTKNOW
1814 LanguageType nTmpKey1 = eLang & 0x7ff, // the main language in many cases DE
1815 nTmpKey2 = eLang & 0x3ff; // otherwise for example EN
1816 String sTemp(sWord);
1818 if(pLangTable->find(eLang) != pLangTable->end() || CreateLanguageFile(eLang, sal_False))
1820 //the language is available - so bring it on
1821 SvxAutoCorrectLanguageLists* pList = pLangTable->find(eLang)->second;
1822 String _sTemp(sWord);
1823 if(pList->GetWrdSttExceptList()->Seek_Entry(&_sTemp))
1824 return sal_True;
1827 // If it still could not be found here, then keep on searching
1828 if(nTmpKey1 != eLang && (pLangTable->find(nTmpKey1) != pLangTable->end() || CreateLanguageFile(nTmpKey1, sal_False)))
1830 //the language is available - so bring it on
1831 SvxAutoCorrectLanguageLists* pList = pLangTable->find(nTmpKey1)->second;
1832 if(pList->GetWrdSttExceptList()->Seek_Entry(&sTemp))
1833 return sal_True;
1836 if(nTmpKey2 != eLang && (pLangTable->find(nTmpKey2) != pLangTable->end() || CreateLanguageFile(nTmpKey2, sal_False)))
1838 //the language is available - so bring it on
1839 SvxAutoCorrectLanguageLists* pList = pLangTable->find(nTmpKey2)->second;
1840 if(pList->GetWrdSttExceptList()->Seek_Entry(&sTemp))
1841 return sal_True;
1844 if(pLangTable->find(LANGUAGE_DONTKNOW) != pLangTable->end() || CreateLanguageFile(LANGUAGE_DONTKNOW, sal_False))
1846 //the language is available - so bring it on
1847 SvxAutoCorrectLanguageLists* pList = pLangTable->find(LANGUAGE_DONTKNOW)->second;
1848 if(pList->GetWrdSttExceptList()->Seek_Entry(&sTemp))
1849 return sal_True;
1851 return sal_False;
1854 static sal_Bool lcl_FindAbbreviation( const SvStringsISortDtor* pList, const String& sWord)
1856 String sAbk( '~' );
1857 sal_uInt16 nPos;
1858 pList->Seek_Entry( &sAbk, &nPos );
1859 if( nPos < pList->Count() )
1861 String sLowerWord( sWord ); sLowerWord.ToLowerAscii();
1862 const String* pAbk;
1863 for( sal_uInt16 n = nPos;
1864 n < pList->Count() &&
1865 '~' == ( pAbk = (*pList)[ n ])->GetChar( 0 );
1866 ++n )
1868 // ~ and ~. are not allowed!
1869 if( 2 < pAbk->Len() && pAbk->Len() - 1 <= sWord.Len() )
1871 String sLowerAbk( *pAbk ); sLowerAbk.ToLowerAscii();
1872 for( xub_StrLen i = sLowerAbk.Len(), ii = sLowerWord.Len(); i; )
1874 if( !--i ) // agrees
1875 return sal_True;
1877 if( sLowerAbk.GetChar( i ) != sLowerWord.GetChar( --ii ))
1878 break;
1883 OSL_ENSURE( !(nPos && '~' == (*pList)[ --nPos ]->GetChar( 0 ) ),
1884 "Wrongly sorted exception list?" );
1885 return sal_False;
1888 sal_Bool SvxAutoCorrect::FindInCplSttExceptList(LanguageType eLang,
1889 const String& sWord, sal_Bool bAbbreviation)
1891 // First search for eLang, then US-English -> English
1892 // and last in LANGUAGE_DONTKNOW
1893 LanguageType nTmpKey1 = eLang & 0x7ff, // the main language in many cases DE
1894 nTmpKey2 = eLang & 0x3ff; // otherwise for example EN
1895 String sTemp( sWord );
1897 if(pLangTable->find(eLang) != pLangTable->end() || CreateLanguageFile(eLang, sal_False))
1899 //the language is available - so bring it on
1900 const SvStringsISortDtor* pList = pLangTable->find(eLang)->second->GetCplSttExceptList();
1901 if(bAbbreviation ? lcl_FindAbbreviation(pList, sWord) : pList->Seek_Entry(&sTemp))
1902 return sal_True;
1905 // If it still could not be found here, then keep on searching
1906 if(nTmpKey1 != eLang && (pLangTable->find(nTmpKey1) != pLangTable->end() || CreateLanguageFile(nTmpKey1, sal_False)))
1908 const SvStringsISortDtor* pList = pLangTable->find(nTmpKey1)->second->GetCplSttExceptList();
1909 if(bAbbreviation ? lcl_FindAbbreviation(pList, sWord) : pList->Seek_Entry(&sTemp))
1910 return sal_True;
1913 if(nTmpKey2 != eLang && (pLangTable->find(nTmpKey2) != pLangTable->end() || CreateLanguageFile(nTmpKey2, sal_False)))
1915 //the language is available - so bring it on
1916 const SvStringsISortDtor* pList = pLangTable->find(nTmpKey2)->second->GetCplSttExceptList();
1917 if(bAbbreviation ? lcl_FindAbbreviation(pList, sWord) : pList->Seek_Entry(&sTemp))
1918 return sal_True;
1921 if(pLangTable->find(LANGUAGE_DONTKNOW) != pLangTable->end() || CreateLanguageFile(LANGUAGE_DONTKNOW, sal_False))
1923 //the language is available - so bring it on
1924 const SvStringsISortDtor* pList = pLangTable->find(LANGUAGE_DONTKNOW)->second->GetCplSttExceptList();
1925 if(bAbbreviation ? lcl_FindAbbreviation(pList, sWord) : pList->Seek_Entry(&sTemp))
1926 return sal_True;
1928 return sal_False;
1931 String SvxAutoCorrect::GetAutoCorrFileName( LanguageType eLang,
1932 sal_Bool bNewFile, sal_Bool bTst ) const
1934 String sRet, sExt( MsLangId::convertLanguageToIsoString( eLang ) );
1935 sExt.Insert('_', 0);
1936 sExt.AppendAscii( ".dat" );
1937 if( bNewFile )
1938 ( sRet = sUserAutoCorrFile ) += sExt;
1939 else if( !bTst )
1940 ( sRet = sShareAutoCorrFile ) += sExt;
1941 else
1943 // test first in the user directory - if not exist, then
1944 ( sRet = sUserAutoCorrFile ) += sExt;
1945 if( !FStatHelper::IsDocument( sRet ))
1946 ( sRet = sShareAutoCorrFile ) += sExt;
1948 return sRet;
1951 SvxAutoCorrectLanguageLists::SvxAutoCorrectLanguageLists(
1952 SvxAutoCorrect& rParent,
1953 const String& rShareAutoCorrectFile,
1954 const String& rUserAutoCorrectFile,
1955 LanguageType eLang)
1956 : sShareAutoCorrFile( rShareAutoCorrectFile ),
1957 sUserAutoCorrFile( rUserAutoCorrectFile ),
1958 aModifiedDate( Date::EMPTY ),
1959 aModifiedTime( Time::EMPTY ),
1960 aLastCheckTime( Time::EMPTY ),
1961 eLanguage(eLang),
1962 pCplStt_ExcptLst( 0 ),
1963 pWrdStt_ExcptLst( 0 ),
1964 pAutocorr_List( 0 ),
1965 rAutoCorrect(rParent),
1966 nFlags(0)
1970 SvxAutoCorrectLanguageLists::~SvxAutoCorrectLanguageLists()
1972 delete pCplStt_ExcptLst;
1973 delete pWrdStt_ExcptLst;
1974 delete pAutocorr_List;
1977 sal_Bool SvxAutoCorrectLanguageLists::IsFileChanged_Imp()
1979 // Access the file system only every 2 minutes to check the date stamp
1980 sal_Bool bRet = sal_False;
1982 Time nMinTime( 0, 2 );
1983 Time nAktTime( Time::SYSTEM );
1984 if( aLastCheckTime > nAktTime || // overflow?
1985 ( nAktTime -= aLastCheckTime ) > nMinTime ) // min time past
1987 Date aTstDate( Date::EMPTY ); Time aTstTime( Time::EMPTY );
1988 if( FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile,
1989 &aTstDate, &aTstTime ) &&
1990 ( aModifiedDate != aTstDate || aModifiedTime != aTstTime ))
1992 bRet = sal_True;
1993 // then remove all the lists fast!
1994 if( CplSttLstLoad & nFlags && pCplStt_ExcptLst )
1995 delete pCplStt_ExcptLst, pCplStt_ExcptLst = 0;
1996 if( WrdSttLstLoad & nFlags && pWrdStt_ExcptLst )
1997 delete pWrdStt_ExcptLst, pWrdStt_ExcptLst = 0;
1998 if( ChgWordLstLoad & nFlags && pAutocorr_List )
1999 delete pAutocorr_List, pAutocorr_List = 0;
2000 nFlags &= ~(CplSttLstLoad | WrdSttLstLoad | ChgWordLstLoad );
2002 aLastCheckTime = Time( Time::SYSTEM );
2004 return bRet;
2007 void SvxAutoCorrectLanguageLists::LoadXMLExceptList_Imp(
2008 SvStringsISortDtor*& rpLst,
2009 const sal_Char* pStrmName,
2010 SotStorageRef& rStg)
2012 if( rpLst )
2013 rpLst->DeleteAndDestroy( 0, rpLst->Count() );
2014 else
2015 rpLst = new SvStringsISortDtor( 16 );
2018 String sStrmName( pStrmName, RTL_TEXTENCODING_MS_1252 );
2019 String sTmp( sStrmName );
2021 if( rStg.Is() && rStg->IsStream( sStrmName ) )
2023 SvStorageStreamRef xStrm = rStg->OpenSotStream( sTmp,
2024 ( STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE ) );
2025 if( SVSTREAM_OK != xStrm->GetError())
2027 xStrm.Clear();
2028 rStg.Clear();
2029 RemoveStream_Imp( sStrmName );
2031 else
2033 uno::Reference< lang::XMultiServiceFactory > xServiceFactory =
2034 comphelper::getProcessServiceFactory();
2035 OSL_ENSURE( xServiceFactory.is(),
2036 "XMLReader::Read: got no service manager" );
2037 if( !xServiceFactory.is() )
2039 // Throw an exception ?
2042 xml::sax::InputSource aParserInput;
2043 aParserInput.sSystemId = sStrmName;
2045 xStrm->Seek( 0L );
2046 xStrm->SetBufferSize( 8 * 1024 );
2047 aParserInput.aInputStream = new utl::OInputStreamWrapper( *xStrm );
2049 // get parser
2050 uno::Reference< XInterface > xXMLParser = xServiceFactory->createInstance(
2051 OUString("com.sun.star.xml.sax.Parser") );
2052 OSL_ENSURE( xXMLParser.is(),
2053 "XMLReader::Read: com.sun.star.xml.sax.Parser service missing" );
2054 if( !xXMLParser.is() )
2056 // Maybe throw an exception?
2059 // get filter
2060 uno::Reference< xml::sax::XDocumentHandler > xFilter = new SvXMLExceptionListImport ( xServiceFactory, *rpLst );
2062 // connect parser and filter
2063 uno::Reference< xml::sax::XParser > xParser( xXMLParser, UNO_QUERY );
2064 xParser->setDocumentHandler( xFilter );
2066 // parse
2069 xParser->parseStream( aParserInput );
2071 catch( const xml::sax::SAXParseException& )
2073 // re throw ?
2075 catch( const xml::sax::SAXException& )
2077 // re throw ?
2079 catch( const io::IOException& )
2081 // re throw ?
2086 // Set time stamp
2087 FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile,
2088 &aModifiedDate, &aModifiedTime );
2089 aLastCheckTime = Time( Time::SYSTEM );
2094 void SvxAutoCorrectLanguageLists::SaveExceptList_Imp(
2095 const SvStringsISortDtor& rLst,
2096 const sal_Char* pStrmName,
2097 SotStorageRef &rStg,
2098 sal_Bool bConvert )
2100 if( rStg.Is() )
2102 String sStrmName( pStrmName, RTL_TEXTENCODING_MS_1252 );
2103 if( !rLst.Count() )
2105 rStg->Remove( sStrmName );
2106 rStg->Commit();
2108 else
2110 SotStorageStreamRef xStrm = rStg->OpenSotStream( sStrmName,
2111 ( STREAM_READ | STREAM_WRITE | STREAM_SHARE_DENYWRITE ) );
2112 if( xStrm.Is() )
2114 xStrm->SetSize( 0 );
2115 xStrm->SetBufferSize( 8192 );
2116 String aPropName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("MediaType") ) );
2117 OUString aMime( "text/xml" );
2118 uno::Any aAny;
2119 aAny <<= aMime;
2120 xStrm->SetProperty( aPropName, aAny );
2123 uno::Reference< lang::XMultiServiceFactory > xServiceFactory =
2124 comphelper::getProcessServiceFactory();
2125 OSL_ENSURE( xServiceFactory.is(),
2126 "XMLReader::Read: got no service manager" );
2127 if( !xServiceFactory.is() )
2129 // Throw an exception ?
2132 uno::Reference < XInterface > xWriter (xServiceFactory->createInstance(
2133 OUString("com.sun.star.xml.sax.Writer")));
2134 OSL_ENSURE(xWriter.is(),"com.sun.star.xml.sax.Writer service missing");
2135 uno::Reference < io::XOutputStream> xOut = new utl::OOutputStreamWrapper( *xStrm );
2136 uno::Reference<io::XActiveDataSource> xSrc(xWriter, uno::UNO_QUERY);
2137 xSrc->setOutputStream(xOut);
2139 uno::Reference<xml::sax::XDocumentHandler> xHandler(xWriter, uno::UNO_QUERY);
2141 SvXMLExceptionListExport aExp( xServiceFactory, rLst, sStrmName, xHandler );
2143 aExp.exportDoc( XML_BLOCK_LIST );
2145 xStrm->Commit();
2146 if( xStrm->GetError() == SVSTREAM_OK )
2148 xStrm.Clear();
2149 if (!bConvert)
2151 rStg->Commit();
2152 if( SVSTREAM_OK != rStg->GetError() )
2154 rStg->Remove( sStrmName );
2155 rStg->Commit();
2164 SvxAutocorrWordList* SvxAutoCorrectLanguageLists::LoadAutocorrWordList()
2166 if( pAutocorr_List )
2167 pAutocorr_List->DeleteAndDestroy( 0, pAutocorr_List->Count() );
2168 else
2169 pAutocorr_List = new SvxAutocorrWordList( 16 );
2173 uno::Reference < embed::XStorage > xStg = comphelper::OStorageHelper::GetStorageFromURL( sShareAutoCorrFile, embed::ElementModes::READ );
2174 String aXMLWordListName( pXMLImplAutocorr_ListStr, RTL_TEXTENCODING_MS_1252 );
2175 uno::Reference < io::XStream > xStrm = xStg->openStreamElement( aXMLWordListName, embed::ElementModes::READ );
2176 uno::Reference< lang::XMultiServiceFactory > xServiceFactory = comphelper::getProcessServiceFactory();
2178 xml::sax::InputSource aParserInput;
2179 aParserInput.sSystemId = aXMLWordListName;
2180 aParserInput.aInputStream = xStrm->getInputStream();
2182 // get parser
2183 uno::Reference< XInterface > xXMLParser = xServiceFactory->createInstance( OUString("com.sun.star.xml.sax.Parser") );
2184 OSL_ENSURE( xXMLParser.is(), "XMLReader::Read: com.sun.star.xml.sax.Parser service missing" );
2185 if( xXMLParser.is() )
2187 RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "AutoCorrect Import" );
2188 uno::Reference< xml::sax::XDocumentHandler > xFilter = new SvXMLAutoCorrectImport( xServiceFactory, pAutocorr_List, rAutoCorrect, xStg );
2190 // connect parser and filter
2191 uno::Reference< xml::sax::XParser > xParser( xXMLParser, UNO_QUERY );
2192 xParser->setDocumentHandler( xFilter );
2194 // parse
2195 xParser->parseStream( aParserInput );
2198 catch ( const uno::Exception& )
2202 // Set time stamp
2203 FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile,
2204 &aModifiedDate, &aModifiedTime );
2205 aLastCheckTime = Time( Time::SYSTEM );
2207 return pAutocorr_List;
2210 void SvxAutoCorrectLanguageLists::SetAutocorrWordList( SvxAutocorrWordList* pList )
2212 if( pAutocorr_List && pList != pAutocorr_List )
2213 delete pAutocorr_List;
2214 pAutocorr_List = pList;
2215 if( !pAutocorr_List )
2217 OSL_ENSURE( !this, "No valid list" );
2218 pAutocorr_List = new SvxAutocorrWordList( 16 );
2220 nFlags |= ChgWordLstLoad;
2223 const SvxAutocorrWordList* SvxAutoCorrectLanguageLists::GetAutocorrWordList()
2225 if( !( ChgWordLstLoad & nFlags ) || IsFileChanged_Imp() )
2226 SetAutocorrWordList( LoadAutocorrWordList() );
2227 return pAutocorr_List;
2230 SvStringsISortDtor* SvxAutoCorrectLanguageLists::GetCplSttExceptList()
2232 if( !( CplSttLstLoad & nFlags ) || IsFileChanged_Imp() )
2233 SetCplSttExceptList( LoadCplSttExceptList() );
2234 return pCplStt_ExcptLst;
2237 sal_Bool SvxAutoCorrectLanguageLists::AddToCplSttExceptList(const String& rNew)
2239 String* pNew = new String( rNew );
2240 if( rNew.Len() && GetCplSttExceptList()->Insert( pNew ) )
2242 MakeUserStorage_Impl();
2243 SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2245 SaveExceptList_Imp( *pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg );
2247 xStg = 0;
2248 // Set time stamp
2249 FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
2250 &aModifiedDate, &aModifiedTime );
2251 aLastCheckTime = Time( Time::SYSTEM );
2253 else
2254 delete pNew, pNew = 0;
2255 return 0 != pNew;
2258 sal_Bool SvxAutoCorrectLanguageLists::AddToWrdSttExceptList(const String& rNew)
2260 String* pNew = new String( rNew );
2261 SvStringsISortDtor* pExceptList = LoadWrdSttExceptList();
2262 if( rNew.Len() && pExceptList && pExceptList->Insert( pNew ) )
2264 MakeUserStorage_Impl();
2265 SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2267 SaveExceptList_Imp( *pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg );
2269 xStg = 0;
2270 // Set time stamp
2271 FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
2272 &aModifiedDate, &aModifiedTime );
2273 aLastCheckTime = Time( Time::SYSTEM );
2275 else
2276 delete pNew, pNew = 0;
2277 return 0 != pNew;
2280 SvStringsISortDtor* SvxAutoCorrectLanguageLists::LoadCplSttExceptList()
2282 SotStorageRef xStg = new SotStorage( sShareAutoCorrFile, STREAM_READ | STREAM_SHARE_DENYNONE, sal_True );
2283 String sTemp ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplCplStt_ExcptLstStr ) );
2284 if( xStg.Is() && xStg->IsContained( sTemp ) )
2285 LoadXMLExceptList_Imp( pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg );
2287 return pCplStt_ExcptLst;
2290 void SvxAutoCorrectLanguageLists::SaveCplSttExceptList()
2292 MakeUserStorage_Impl();
2293 SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2295 SaveExceptList_Imp( *pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg );
2297 xStg = 0;
2299 // Set time stamp
2300 FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
2301 &aModifiedDate, &aModifiedTime );
2302 aLastCheckTime = Time( Time::SYSTEM );
2305 void SvxAutoCorrectLanguageLists::SetCplSttExceptList( SvStringsISortDtor* pList )
2307 if( pCplStt_ExcptLst && pList != pCplStt_ExcptLst )
2308 delete pCplStt_ExcptLst;
2310 pCplStt_ExcptLst = pList;
2311 if( !pCplStt_ExcptLst )
2313 OSL_ENSURE( !this, "No valid list" );
2314 pCplStt_ExcptLst = new SvStringsISortDtor( 16 );
2316 nFlags |= CplSttLstLoad;
2319 SvStringsISortDtor* SvxAutoCorrectLanguageLists::LoadWrdSttExceptList()
2321 SotStorageRef xStg = new SotStorage( sShareAutoCorrFile, STREAM_READ | STREAM_SHARE_DENYNONE, sal_True );
2322 String sTemp ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplWrdStt_ExcptLstStr ) );
2323 if( xStg.Is() && xStg->IsContained( sTemp ) )
2324 LoadXMLExceptList_Imp( pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg );
2325 return pWrdStt_ExcptLst;
2328 void SvxAutoCorrectLanguageLists::SaveWrdSttExceptList()
2330 MakeUserStorage_Impl();
2331 SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2333 SaveExceptList_Imp( *pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg );
2335 xStg = 0;
2336 // Set time stamp
2337 FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
2338 &aModifiedDate, &aModifiedTime );
2339 aLastCheckTime = Time( Time::SYSTEM );
2342 void SvxAutoCorrectLanguageLists::SetWrdSttExceptList( SvStringsISortDtor* pList )
2344 if( pWrdStt_ExcptLst && pList != pWrdStt_ExcptLst )
2345 delete pWrdStt_ExcptLst;
2346 pWrdStt_ExcptLst = pList;
2347 if( !pWrdStt_ExcptLst )
2349 OSL_ENSURE( !this, "No valid list" );
2350 pWrdStt_ExcptLst = new SvStringsISortDtor( 16 );
2352 nFlags |= WrdSttLstLoad;
2355 SvStringsISortDtor* SvxAutoCorrectLanguageLists::GetWrdSttExceptList()
2357 if( !( WrdSttLstLoad & nFlags ) || IsFileChanged_Imp() )
2358 SetWrdSttExceptList( LoadWrdSttExceptList() );
2359 return pWrdStt_ExcptLst;
2362 void SvxAutoCorrectLanguageLists::RemoveStream_Imp( const String& rName )
2364 if( sShareAutoCorrFile != sUserAutoCorrFile )
2366 SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2367 if( xStg.Is() && SVSTREAM_OK == xStg->GetError() &&
2368 xStg->IsStream( rName ) )
2370 xStg->Remove( rName );
2371 xStg->Commit();
2373 xStg = 0;
2378 void SvxAutoCorrectLanguageLists::MakeUserStorage_Impl()
2380 // The conversion needs to happen if the file is already in the user
2381 // directory and is in the old format. Additionally it needs to
2382 // happen when the file is being copied from share to user.
2384 sal_Bool bError = sal_False, bConvert = sal_False, bCopy = sal_False;
2385 INetURLObject aDest;
2386 INetURLObject aSource;
2388 if (sUserAutoCorrFile != sShareAutoCorrFile )
2390 aSource = INetURLObject ( sShareAutoCorrFile );
2391 aDest = INetURLObject ( sUserAutoCorrFile );
2392 if ( SotStorage::IsOLEStorage ( sShareAutoCorrFile ) )
2394 aDest.SetExtension ( String::CreateFromAscii ( "bak" ) );
2395 bConvert = sal_True;
2397 bCopy = sal_True;
2399 else if ( SotStorage::IsOLEStorage ( sUserAutoCorrFile ) )
2401 aSource = INetURLObject ( sUserAutoCorrFile );
2402 aDest = INetURLObject ( sUserAutoCorrFile );
2403 aDest.SetExtension ( String::CreateFromAscii ( "bak" ) );
2404 bCopy = bConvert = sal_True;
2406 if (bCopy)
2410 String sMain(aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ));
2411 sal_Unicode cSlash = '/';
2412 xub_StrLen nSlashPos = sMain.SearchBackward(cSlash);
2413 sMain.Erase(nSlashPos);
2414 ::ucbhelper::Content aNewContent( sMain, uno::Reference< XCommandEnvironment > ());
2415 Any aAny;
2416 TransferInfo aInfo;
2417 aInfo.NameClash = NameClash::OVERWRITE;
2418 aInfo.NewTitle = aDest.GetName();
2419 aInfo.SourceURL = aSource.GetMainURL( INetURLObject::DECODE_TO_IURI );
2420 aInfo.MoveData = sal_False;
2421 aAny <<= aInfo;
2422 aNewContent.executeCommand( OUString ( "transfer" ), aAny);
2424 catch (...)
2426 bError = sal_True;
2429 if (bConvert && !bError)
2431 SotStorageRef xSrcStg = new SotStorage( aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ), STREAM_READ, sal_True );
2432 SotStorageRef xDstStg = new SotStorage( sUserAutoCorrFile, STREAM_WRITE, sal_True );
2434 if( xSrcStg.Is() && xDstStg.Is() )
2436 String sWord ( RTL_CONSTASCII_USTRINGPARAM ( pImplWrdStt_ExcptLstStr ) );
2437 String sSentence ( RTL_CONSTASCII_USTRINGPARAM ( pImplCplStt_ExcptLstStr ) );
2438 String sXMLWord ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplWrdStt_ExcptLstStr ) );
2439 String sXMLSentence ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplCplStt_ExcptLstStr ) );
2440 SvStringsISortDtor *pTmpWordList = NULL;
2442 if (xSrcStg->IsContained( sXMLWord ) )
2443 LoadXMLExceptList_Imp( pTmpWordList, pXMLImplWrdStt_ExcptLstStr, xSrcStg );
2445 if (pTmpWordList)
2447 SaveExceptList_Imp( *pTmpWordList, pXMLImplWrdStt_ExcptLstStr, xDstStg, sal_True );
2448 pTmpWordList->DeleteAndDestroy( 0, pTmpWordList->Count() );
2449 pTmpWordList = NULL;
2453 if (xSrcStg->IsContained( sXMLSentence ) )
2454 LoadXMLExceptList_Imp( pTmpWordList, pXMLImplCplStt_ExcptLstStr, xSrcStg );
2456 if (pTmpWordList)
2458 SaveExceptList_Imp( *pTmpWordList, pXMLImplCplStt_ExcptLstStr, xDstStg, sal_True );
2459 pTmpWordList->DeleteAndDestroy( 0, pTmpWordList->Count() );
2462 GetAutocorrWordList();
2463 MakeBlocklist_Imp( *xDstStg );
2464 sShareAutoCorrFile = sUserAutoCorrFile;
2465 xDstStg = 0;
2468 ::ucbhelper::Content aContent ( aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ), uno::Reference < XCommandEnvironment > ());
2469 aContent.executeCommand ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "delete" ) ), makeAny ( sal_Bool (sal_True ) ) );
2471 catch (...)
2476 else if( bCopy && !bError )
2477 sShareAutoCorrFile = sUserAutoCorrFile;
2480 sal_Bool SvxAutoCorrectLanguageLists::MakeBlocklist_Imp( SvStorage& rStg )
2482 String sStrmName( pXMLImplAutocorr_ListStr, RTL_TEXTENCODING_MS_1252 );
2483 sal_Bool bRet = sal_True, bRemove = !pAutocorr_List || !pAutocorr_List->Count();
2484 if( !bRemove )
2486 SvStorageStreamRef refList = rStg.OpenSotStream( sStrmName,
2487 ( STREAM_READ | STREAM_WRITE | STREAM_SHARE_DENYWRITE ) );
2488 if( refList.Is() )
2490 refList->SetSize( 0 );
2491 refList->SetBufferSize( 8192 );
2492 String aPropName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("MediaType") ) );
2493 OUString aMime( "text/xml" );
2494 uno::Any aAny;
2495 aAny <<= aMime;
2496 refList->SetProperty( aPropName, aAny );
2498 uno::Reference< lang::XMultiServiceFactory > xServiceFactory =
2499 comphelper::getProcessServiceFactory();
2500 OSL_ENSURE( xServiceFactory.is(),
2501 "XMLReader::Read: got no service manager" );
2502 if( !xServiceFactory.is() )
2504 // Throw an exception ?
2507 uno::Reference < XInterface > xWriter (xServiceFactory->createInstance(
2508 OUString("com.sun.star.xml.sax.Writer")));
2509 OSL_ENSURE(xWriter.is(),"com.sun.star.xml.sax.Writer service missing");
2510 uno::Reference < io::XOutputStream> xOut = new utl::OOutputStreamWrapper( *refList );
2511 uno::Reference<io::XActiveDataSource> xSrc(xWriter, uno::UNO_QUERY);
2512 xSrc->setOutputStream(xOut);
2514 uno::Reference<xml::sax::XDocumentHandler> xHandler(xWriter, uno::UNO_QUERY);
2516 SvXMLAutoCorrectExport aExp( xServiceFactory, pAutocorr_List, sStrmName, xHandler );
2518 aExp.exportDoc( XML_BLOCK_LIST );
2520 refList->Commit();
2521 bRet = SVSTREAM_OK == refList->GetError();
2522 if( bRet )
2524 refList.Clear();
2525 rStg.Commit();
2526 if( SVSTREAM_OK != rStg.GetError() )
2528 bRemove = sal_True;
2529 bRet = sal_False;
2533 else
2534 bRet = sal_False;
2537 if( bRemove )
2539 rStg.Remove( sStrmName );
2540 rStg.Commit();
2543 return bRet;
2546 sal_Bool SvxAutoCorrectLanguageLists::PutText( const String& rShort,
2547 const String& rLong )
2549 // First get the current list!
2550 GetAutocorrWordList();
2552 MakeUserStorage_Impl();
2553 SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2555 sal_Bool bRet = xStg.Is() && SVSTREAM_OK == xStg->GetError();
2557 // Update the word list
2558 if( bRet )
2560 sal_uInt16 nPos;
2561 SvxAutocorrWord* pNew = new SvxAutocorrWord( rShort, rLong, sal_True );
2562 if( pAutocorr_List->Seek_Entry( pNew, &nPos ) )
2564 if( !(*pAutocorr_List)[ nPos ]->IsTextOnly() )
2566 // Still have to remove the Storage
2567 String sStgNm( rShort );
2568 if (xStg->IsOLEStorage())
2569 EncryptBlockName_Imp( sStgNm );
2570 else
2571 GeneratePackageName ( rShort, sStgNm);
2573 if( xStg->IsContained( sStgNm ) )
2574 xStg->Remove( sStgNm );
2576 pAutocorr_List->DeleteAndDestroy( nPos );
2579 if( pAutocorr_List->Insert( pNew ) )
2581 bRet = MakeBlocklist_Imp( *xStg );
2582 xStg = 0;
2584 else
2586 delete pNew;
2587 bRet = sal_False;
2590 return bRet;
2593 sal_Bool SvxAutoCorrectLanguageLists::PutText( const String& rShort,
2594 SfxObjectShell& rShell )
2596 // First get the current list!
2597 GetAutocorrWordList();
2599 MakeUserStorage_Impl();
2601 sal_Bool bRet = sal_False;
2602 String sLong;
2605 uno::Reference < embed::XStorage > xStg = comphelper::OStorageHelper::GetStorageFromURL( sUserAutoCorrFile, embed::ElementModes::READWRITE );
2606 bRet = rAutoCorrect.PutText( xStg, sUserAutoCorrFile, rShort, rShell, sLong );
2607 xStg = 0;
2609 // Update the word list
2610 if( bRet )
2612 SvxAutocorrWord* pNew = new SvxAutocorrWord( rShort, sLong, sal_False );
2613 if( pAutocorr_List->Insert( pNew ) )
2615 SotStorageRef xStor = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2616 MakeBlocklist_Imp( *xStor );
2618 else
2619 delete pNew;
2622 catch ( const uno::Exception& )
2626 return bRet;
2629 // Delete an entry
2630 sal_Bool SvxAutoCorrectLanguageLists::DeleteText( const String& rShort )
2632 // First get the current list!
2633 GetAutocorrWordList();
2635 MakeUserStorage_Impl();
2637 SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, sal_True );
2638 sal_Bool bRet = xStg.Is() && SVSTREAM_OK == xStg->GetError();
2639 if( bRet )
2641 sal_uInt16 nPos;
2642 SvxAutocorrWord aTmp( rShort, rShort );
2643 if( pAutocorr_List->Seek_Entry( &aTmp, &nPos ) )
2645 SvxAutocorrWord* pFnd = (*pAutocorr_List)[ nPos ];
2646 if( !pFnd->IsTextOnly() )
2648 String aName( rShort );
2649 if (xStg->IsOLEStorage())
2650 EncryptBlockName_Imp( aName );
2651 else
2652 GeneratePackageName ( rShort, aName );
2653 if( xStg->IsContained( aName ) )
2655 xStg->Remove( aName );
2656 bRet = xStg->Commit();
2660 // Update the word list
2661 pAutocorr_List->DeleteAndDestroy( nPos );
2662 MakeBlocklist_Imp( *xStg );
2663 xStg = 0;
2665 else
2666 bRet = sal_False;
2668 return bRet;
2671 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */