1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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/componentcontext.hxx>
40 #include <comphelper/processfactory.hxx>
41 #include <comphelper/storagehelper.hxx>
42 #include <comphelper/string.hxx>
43 #include <editeng/editids.hrc>
44 #include <sot/storage.hxx>
45 #include <editeng/udlnitem.hxx>
46 #include <editeng/wghtitem.hxx>
47 #include <editeng/escapementitem.hxx>
48 #include <editeng/svxacorr.hxx>
49 #include <editeng/unolingu.hxx>
50 #include "vcl/window.hxx"
52 #include <com/sun/star/xml/sax/InputSource.hpp>
53 #include <com/sun/star/xml/sax/Parser.hpp>
54 #include <com/sun/star/xml/sax/Writer.hpp>
55 #include <unotools/streamwrap.hxx>
56 #include <SvXMLAutoCorrectImport.hxx>
57 #include <SvXMLAutoCorrectExport.hxx>
58 #include <ucbhelper/content.hxx>
59 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
60 #include <com/sun/star/ucb/TransferInfo.hpp>
61 #include <com/sun/star/ucb/NameClash.hpp>
62 #include <xmloff/xmltoken.hxx>
63 #include <vcl/help.hxx>
64 #include <rtl/logfile.hxx>
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
;
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 static const sal_Unicode cNonBreakingSpace
= 0xA0;
79 static const sal_Char pImplAutocorr_ListStr
[] = "DocumentList";
80 static const sal_Char pXMLImplWrdStt_ExcptLstStr
[] = "WordExceptList.xml";
81 static const sal_Char pXMLImplCplStt_ExcptLstStr
[] = "SentenceExceptList.xml";
82 static const sal_Char pXMLImplAutocorr_ListStr
[] = "DocumentList.xml";
85 /* also at these beginnings - Brackets and all kinds of begin characters */
86 sImplSttSkipChars
[] = "\"\'([{\x83\x84\x89\x91\x92\x93\x94",
87 /* also at these ends - Brackets and all kinds of begin characters */
88 sImplEndSkipChars
[] = "\"\')]}\x83\x84\x89\x91\x92\x93\x94";
90 // These characters are allowed in words: (for FnCptlSttSntnc)
91 static const sal_Char sImplWordChars
[] = "-'";
93 void EncryptBlockName_Imp( String
& rName
);
95 TYPEINIT0(SvxAutoCorrect
)
97 typedef SvxAutoCorrectLanguageLists
* SvxAutoCorrectLanguageListsPtr
;
99 static inline int IsWordDelim( const sal_Unicode c
)
101 return ' ' == c
|| '\t' == c
|| 0x0a == c
||
102 cNonBreakingSpace
== c
|| 0x2011 == c
|| 0x1 == c
;
105 static inline int IsLowerLetter( sal_Int32 nCharType
)
107 return CharClass::isLetterType( nCharType
) &&
108 0 == ( ::com::sun::star::i18n::KCharacterType::UPPER
& nCharType
);
111 static inline int IsUpperLetter( sal_Int32 nCharType
)
113 return CharClass::isLetterType( nCharType
) &&
114 0 == ( ::com::sun::star::i18n::KCharacterType::LOWER
& nCharType
);
117 bool lcl_IsUnsupportedUnicodeChar( CharClass
& rCC
, const String
& rTxt
,
118 xub_StrLen nStt
, xub_StrLen nEnd
)
120 for( ; nStt
< nEnd
; ++nStt
)
122 short nScript
= rCC
.getScript( rTxt
, nStt
);
125 case ::com::sun::star::i18n::UnicodeScript_kCJKRadicalsSupplement
:
126 case ::com::sun::star::i18n::UnicodeScript_kHangulJamo
:
127 case ::com::sun::star::i18n::UnicodeScript_kCJKSymbolPunctuation
:
128 case ::com::sun::star::i18n::UnicodeScript_kHiragana
:
129 case ::com::sun::star::i18n::UnicodeScript_kKatakana
:
130 case ::com::sun::star::i18n::UnicodeScript_kHangulCompatibilityJamo
:
131 case ::com::sun::star::i18n::UnicodeScript_kEnclosedCJKLetterMonth
:
132 case ::com::sun::star::i18n::UnicodeScript_kCJKCompatibility
:
133 case ::com::sun::star::i18n::UnicodeScript_k_CJKUnifiedIdeographsExtensionA
:
134 case ::com::sun::star::i18n::UnicodeScript_kCJKUnifiedIdeograph
:
135 case ::com::sun::star::i18n::UnicodeScript_kHangulSyllable
:
136 case ::com::sun::star::i18n::UnicodeScript_kCJKCompatibilityIdeograph
:
137 case ::com::sun::star::i18n::UnicodeScript_kHalfwidthFullwidthForm
:
139 default: ; //do nothing
145 static sal_Bool
lcl_IsSymbolChar( CharClass
& rCC
, const String
& rTxt
,
146 xub_StrLen nStt
, xub_StrLen nEnd
)
148 for( ; nStt
< nEnd
; ++nStt
)
150 if( ::com::sun::star::i18n::UnicodeType::PRIVATE_USE
==
151 rCC
.getType( rTxt
, nStt
))
157 static sal_Bool
lcl_IsInAsciiArr( const sal_Char
* pArr
, const sal_Unicode c
)
159 sal_Bool bRet
= sal_False
;
160 for( ; *pArr
; ++pArr
)
169 SvxAutoCorrDoc::~SvxAutoCorrDoc()
173 // Called by the functions:
176 // after the exchange of characters. Then the words, if necessary, can be inserted
177 // into the exception list.
178 void SvxAutoCorrDoc::SaveCpltSttWord( sal_uLong
, xub_StrLen
, const String
&,
183 LanguageType
SvxAutoCorrDoc::GetLanguage( xub_StrLen
, sal_Bool
) const
185 return LANGUAGE_SYSTEM
;
188 static const LanguageTag
& GetAppLang()
190 return Application::GetSettings().GetLanguageTag();
192 static LocaleDataWrapper
& GetLocaleDataWrapper( sal_uInt16 nLang
)
194 static LocaleDataWrapper
aLclDtWrp( GetAppLang() );
195 LanguageTag
aLcl( nLang
);
196 const LanguageTag
& rLcl
= aLclDtWrp
.getLoadedLanguageTag();
198 aLclDtWrp
.setLanguageTag( aLcl
);
201 static TransliterationWrapper
& GetIgnoreTranslWrapper()
203 static int bIsInit
= 0;
204 static TransliterationWrapper
aWrp( ::comphelper::getProcessComponentContext(),
205 ::com::sun::star::i18n::TransliterationModules_IGNORE_KANA
|
206 ::com::sun::star::i18n::TransliterationModules_IGNORE_WIDTH
);
209 aWrp
.loadModuleIfNeeded( GetAppLang().getLanguageType() );
214 static CollatorWrapper
& GetCollatorWrapper()
216 static int bIsInit
= 0;
217 static CollatorWrapper
aCollWrp( ::comphelper::getProcessComponentContext() );
220 aCollWrp
.loadDefaultCollator( GetAppLang().getLocale(), 0 );
226 static void lcl_ClearTable(boost::ptr_map
<LanguageType
, SvxAutoCorrectLanguageLists
>& rLangTable
)
231 sal_Bool
SvxAutoCorrect::IsAutoCorrectChar( sal_Unicode cChar
)
233 return cChar
== '\0' || cChar
== '\t' || cChar
== 0x0a ||
234 cChar
== ' ' || cChar
== '\'' || cChar
== '\"' ||
235 cChar
== '*' || cChar
== '_' || cChar
== '%' ||
236 cChar
== '.' || cChar
== ',' || cChar
== ';' ||
237 cChar
== ':' || cChar
== '?' || cChar
== '!' ||
238 cChar
== '/' || cChar
== '-';
241 sal_Bool
SvxAutoCorrect::NeedsHardspaceAutocorr( sal_Unicode cChar
)
243 return cChar
== '%' || cChar
== ';' || cChar
== ':' || cChar
== '?' || cChar
== '!' ||
244 cChar
== '/' /*case for the urls exception*/;
247 long SvxAutoCorrect::GetDefaultFlags()
249 long nRet
= Autocorrect
261 LanguageType eLang
= GetAppLang().getLanguageType();
264 case LANGUAGE_ENGLISH
:
265 case LANGUAGE_ENGLISH_US
:
266 case LANGUAGE_ENGLISH_UK
:
267 case LANGUAGE_ENGLISH_AUS
:
268 case LANGUAGE_ENGLISH_CAN
:
269 case LANGUAGE_ENGLISH_NZ
:
270 case LANGUAGE_ENGLISH_EIRE
:
271 case LANGUAGE_ENGLISH_SAFRICA
:
272 case LANGUAGE_ENGLISH_JAMAICA
:
273 case LANGUAGE_ENGLISH_CARRIBEAN
:
274 nRet
&= ~(ChgQuotes
|ChgSglQuotes
);
281 SvxAutoCorrect::SvxAutoCorrect( const String
& rShareAutocorrFile
,
282 const String
& rUserAutocorrFile
)
283 : sShareAutoCorrFile( rShareAutocorrFile
),
284 sUserAutoCorrFile( rUserAutocorrFile
),
285 pLangTable( new boost::ptr_map
<LanguageType
, SvxAutoCorrectLanguageLists
> ),
286 pCharClass( 0 ), bRunNext( false ),
287 cStartDQuote( 0 ), cEndDQuote( 0 ), cStartSQuote( 0 ), cEndSQuote( 0 )
289 nFlags
= SvxAutoCorrect::GetDefaultFlags();
295 SvxAutoCorrect::SvxAutoCorrect( const SvxAutoCorrect
& rCpy
)
296 : sShareAutoCorrFile( rCpy
.sShareAutoCorrFile
),
297 sUserAutoCorrFile( rCpy
.sUserAutoCorrFile
),
299 aSwFlags( rCpy
.aSwFlags
),
301 pLangTable( new boost::ptr_map
<LanguageType
, SvxAutoCorrectLanguageLists
> ),
302 pCharClass( 0 ), bRunNext( false ),
304 nFlags( rCpy
.nFlags
& ~(ChgWordLstLoad
|CplSttLstLoad
|WrdSttLstLoad
)),
305 cStartDQuote( rCpy
.cStartDQuote
), cEndDQuote( rCpy
.cEndDQuote
),
306 cStartSQuote( rCpy
.cStartSQuote
), cEndSQuote( rCpy
.cEndSQuote
),
307 cEmDash( rCpy
.cEmDash
), cEnDash( rCpy
.cEnDash
)
312 SvxAutoCorrect::~SvxAutoCorrect()
314 lcl_ClearTable(*pLangTable
);
319 void SvxAutoCorrect::_GetCharClass( LanguageType eLang
)
322 pCharClass
= new CharClass( LanguageTag( eLang
));
323 eCharClassLang
= eLang
;
326 void SvxAutoCorrect::SetAutoCorrFlag( long nFlag
, sal_Bool bOn
)
329 nFlags
= bOn
? nFlags
| nFlag
334 if( (nOld
& CptlSttSntnc
) != (nFlags
& CptlSttSntnc
) )
335 nFlags
&= ~CplSttLstLoad
;
336 if( (nOld
& CptlSttWrd
) != (nFlags
& CptlSttWrd
) )
337 nFlags
&= ~WrdSttLstLoad
;
338 if( (nOld
& Autocorrect
) != (nFlags
& Autocorrect
) )
339 nFlags
&= ~ChgWordLstLoad
;
344 // Two capital letters at the beginning of word?
345 sal_Bool
SvxAutoCorrect::FnCptlSttWrd( SvxAutoCorrDoc
& rDoc
, const String
& rTxt
,
346 xub_StrLen nSttPos
, xub_StrLen nEndPos
,
349 sal_Bool bRet
= sal_False
;
350 CharClass
& rCC
= GetCharClass( eLang
);
352 // Delete all non alphanumeric. Test the characters at the beginning/end of
353 // the word ( recognizes: "(min.", "/min.", and so on.)
354 for( ; nSttPos
< nEndPos
; ++nSttPos
)
355 if( rCC
.isLetterNumeric( rTxt
, nSttPos
))
357 for( ; nSttPos
< nEndPos
; --nEndPos
)
358 if( rCC
.isLetterNumeric( rTxt
, nEndPos
- 1 ))
361 // Is the word a compounded word separated by delimiters?
362 // If so, keep track of all delimiters so each constituent
363 // word can be checked for two initial capital letters.
365 std::deque
<xub_StrLen
> aDelimiters
;
367 // Always check for two capitals at the beginning
368 // of the entire word, so start at nSttPos.
369 aDelimiters
.push_back(nSttPos
);
371 // Find all compound word delimiters
372 for (n
= nSttPos
; n
< nEndPos
; n
++)
374 if (IsAutoCorrectChar(rTxt
.GetChar( n
)))
376 aDelimiters
.push_back( n
+ 1 ); // Get position of char after delimiter
381 // Decide where to put the terminating delimiter.
382 // If the last AutoCorrect char was a newline, then the AutoCorrect
383 // char will not be included in rTxt.
384 // If the last AutoCorrect char was not a newline, then the AutoCorrect
385 // character will be the last character in rTxt.
386 if (!IsAutoCorrectChar(rTxt
.GetChar(nEndPos
-1)))
387 aDelimiters
.push_back(nEndPos
);
389 // Iterate through the word and all words that compose it.
390 n
= aDelimiters
.size();
392 // Two capital letters at the beginning of word?
393 for(n
= 0; n
< aDelimiters
.size() - 1; n
++)
395 nSttPos
= aDelimiters
[n
];
396 nEndPos
= aDelimiters
[n
+ 1];
398 if( nSttPos
+2 < nEndPos
&&
399 IsUpperLetter( rCC
.getCharacterType( rTxt
, nSttPos
)) &&
400 IsUpperLetter( rCC
.getCharacterType( rTxt
, ++nSttPos
)) &&
401 // Is the third character a lower case
402 IsLowerLetter( rCC
.getCharacterType( rTxt
, nSttPos
+1 )) &&
403 // Do not replace special attributes
404 0x1 != rTxt
.GetChar( nSttPos
) && 0x2 != rTxt
.GetChar( nSttPos
))
406 // test if the word is in an exception list
407 String
sWord( rTxt
.Copy( nSttPos
- 1, nEndPos
- nSttPos
+ 1 ));
408 if( !FindInWrdSttExceptList(eLang
, sWord
) )
410 // Check that word isn't correctly spelled before correcting:
411 ::com::sun::star::uno::Reference
<
412 ::com::sun::star::linguistic2::XSpellChecker1
> xSpeller
=
413 SvxGetSpellChecker();
414 if( xSpeller
->hasLanguage(eLang
) )
416 Sequence
< ::com::sun::star::beans::PropertyValue
> aEmptySeq
;
417 if (!xSpeller
->spell(sWord
, eLang
, aEmptySeq
).is())
422 sal_Unicode cSave
= rTxt
.GetChar( nSttPos
);
423 OUString
sChar( cSave
);
424 sChar
= rCC
.lowercase( sChar
);
425 if( sChar
[0] != cSave
&& rDoc
.ReplaceRange( nSttPos
, 1, sChar
))
427 if( SaveWordWrdSttLst
& nFlags
)
428 rDoc
.SaveCpltSttWord( CptlSttWrd
, nSttPos
, sWord
, cSave
);
438 sal_Bool
SvxAutoCorrect::FnChgOrdinalNumber(
439 SvxAutoCorrDoc
& rDoc
, const String
& rTxt
,
440 xub_StrLen nSttPos
, xub_StrLen nEndPos
,
443 // 1st, 2nd, 3rd, 4 - 0th
446 CharClass
& rCC
= GetCharClass( eLang
);
447 sal_Bool bChg
= sal_False
;
449 for( ; nSttPos
< nEndPos
; ++nSttPos
)
450 if( !lcl_IsInAsciiArr( sImplSttSkipChars
, rTxt
.GetChar( nSttPos
) ))
452 for( ; nSttPos
< nEndPos
; --nEndPos
)
453 if( !lcl_IsInAsciiArr( sImplEndSkipChars
, rTxt
.GetChar( nEndPos
- 1 ) ))
457 // Get the last number in the string to check
458 xub_StrLen nNumEnd
= nEndPos
;
459 bool foundEnd
= false;
460 bool validNumber
= true;
461 xub_StrLen i
= nEndPos
;
463 while ( i
> nSttPos
)
466 bool isDigit
= rCC
.isDigit( rTxt
, i
);
468 validNumber
|= isDigit
;
470 if ( isDigit
&& !foundEnd
)
477 if ( foundEnd
&& validNumber
) {
478 sal_Int32 nNum
= rTxt
.Copy( nSttPos
, nNumEnd
- nSttPos
+ 1 ).ToInt32( );
480 // Check if the characters after that number correspond to the ordinal suffix
481 uno::Reference
< i18n::XOrdinalSuffix
> xOrdSuffix
482 = i18n::OrdinalSuffix::create( comphelper::getProcessComponentContext() );
484 uno::Sequence
< OUString
> aSuffixes
= xOrdSuffix
->getOrdinalSuffix( nNum
, rCC
.getLanguageTag().getLocale( ) );
485 for ( sal_Int32 nSuff
= 0; nSuff
< aSuffixes
.getLength(); nSuff
++ )
487 String
sSuffix( aSuffixes
[ nSuff
] );
488 String sEnd
= rTxt
.Copy( nNumEnd
+ 1, nEndPos
- nNumEnd
- 1 );
490 if ( sSuffix
== sEnd
)
492 // Check if the ordinal suffix has to be set as super script
493 if ( rCC
.isLetter( sSuffix
) )
496 SvxEscapementItem
aSvxEscapementItem( DFLT_ESC_AUTO_SUPER
,
497 DFLT_ESC_PROP
, SID_ATTR_CHAR_ESCAPEMENT
);
498 rDoc
.SetAttr( nNumEnd
+ 1 , nEndPos
,
499 SID_ATTR_CHAR_ESCAPEMENT
,
509 sal_Bool
SvxAutoCorrect::FnChgToEnEmDash(
510 SvxAutoCorrDoc
& rDoc
, const String
& rTxt
,
511 xub_StrLen nSttPos
, xub_StrLen nEndPos
,
514 sal_Bool bRet
= sal_False
;
515 CharClass
& rCC
= GetCharClass( eLang
);
516 if (eLang
== LANGUAGE_SYSTEM
)
517 eLang
= GetAppLang().getLanguageType();
518 bool bAlwaysUseEmDash
= (cEmDash
&& (eLang
== LANGUAGE_RUSSIAN
|| eLang
== LANGUAGE_UKRAINIAN
));
520 // replace " - " or " --" with "enDash"
521 if( cEnDash
&& 1 < nSttPos
&& 1 <= nEndPos
- nSttPos
)
523 sal_Unicode cCh
= rTxt
.GetChar( nSttPos
);
526 if( ' ' == rTxt
.GetChar( nSttPos
-1 ) &&
527 '-' == rTxt
.GetChar( nSttPos
+1 ))
530 for( n
= nSttPos
+2; n
< nEndPos
&& lcl_IsInAsciiArr(
531 sImplSttSkipChars
,(cCh
= rTxt
.GetChar( n
)));
535 // found: " --[<AnySttChars>][A-z0-9]
536 if( rCC
.isLetterNumeric( OUString(cCh
) ) )
538 for( n
= nSttPos
-1; n
&& lcl_IsInAsciiArr(
539 sImplEndSkipChars
,(cCh
= rTxt
.GetChar( --n
))); )
542 // found: "[A-z0-9][<AnyEndChars>] --[<AnySttChars>][A-z0-9]
543 if( rCC
.isLetterNumeric( OUString(cCh
) ))
545 rDoc
.Delete( nSttPos
, nSttPos
+ 2 );
546 rDoc
.Insert( nSttPos
, bAlwaysUseEmDash
? OUString(cEmDash
) : OUString(cEnDash
) );
552 else if( 3 < nSttPos
&&
553 ' ' == rTxt
.GetChar( nSttPos
-1 ) &&
554 '-' == rTxt
.GetChar( nSttPos
-2 ))
556 xub_StrLen n
, nLen
= 1, nTmpPos
= nSttPos
- 2;
557 if( '-' == ( cCh
= rTxt
.GetChar( nTmpPos
-1 )) )
561 cCh
= rTxt
.GetChar( nTmpPos
-1 );
565 for( n
= nSttPos
; n
< nEndPos
&& lcl_IsInAsciiArr(
566 sImplSttSkipChars
,(cCh
= rTxt
.GetChar( n
)));
570 // found: " - [<AnySttChars>][A-z0-9]
571 if( rCC
.isLetterNumeric( OUString(cCh
) ) )
574 for( n
= nTmpPos
-1; n
&& lcl_IsInAsciiArr(
575 sImplEndSkipChars
,(cCh
= rTxt
.GetChar( --n
))); )
577 // found: "[A-z0-9][<AnyEndChars>] - [<AnySttChars>][A-z0-9]
578 if( rCC
.isLetterNumeric( OUString(cCh
) ))
580 rDoc
.Delete( nTmpPos
, nTmpPos
+ nLen
);
581 rDoc
.Insert( nTmpPos
, bAlwaysUseEmDash
? OUString(cEmDash
) : OUString(cEnDash
) );
589 // Replace [A-z0-9]--[A-z0-9] double dash with "emDash" or "enDash".
590 // Finnish and Hungarian use enDash instead of emDash.
591 bool bEnDash
= (eLang
== LANGUAGE_HUNGARIAN
|| eLang
== LANGUAGE_FINNISH
);
592 if( ((cEmDash
&& !bEnDash
) || (cEnDash
&& bEnDash
)) && 4 <= nEndPos
- nSttPos
)
594 String
sTmp( rTxt
.Copy( nSttPos
, nEndPos
- nSttPos
) );
595 xub_StrLen nFndPos
= sTmp
.SearchAscii( "--" );
596 if( STRING_NOTFOUND
!= nFndPos
&& nFndPos
&&
597 nFndPos
+ 2 < sTmp
.Len() &&
598 ( rCC
.isLetterNumeric( sTmp
, nFndPos
- 1 ) ||
599 lcl_IsInAsciiArr( sImplEndSkipChars
, rTxt
.GetChar( nFndPos
- 1 ) )) &&
600 ( rCC
.isLetterNumeric( sTmp
, nFndPos
+ 2 ) ||
601 lcl_IsInAsciiArr( sImplSttSkipChars
, rTxt
.GetChar( nFndPos
+ 2 ) )))
603 nSttPos
= nSttPos
+ nFndPos
;
604 rDoc
.Delete( nSttPos
, nSttPos
+ 2 );
605 rDoc
.Insert( nSttPos
, (bEnDash
? OUString(cEnDash
) : OUString(cEmDash
)) );
613 #pragma warning(push)
614 #pragma warning(disable: 4706) // assignment within conditional expression
617 sal_Bool
SvxAutoCorrect::FnAddNonBrkSpace(
618 SvxAutoCorrDoc
& rDoc
, const String
& rTxt
,
619 xub_StrLen
, xub_StrLen nEndPos
,
624 CharClass
& rCC
= GetCharClass( eLang
);
625 const lang::Locale rLocale
= rCC
.getLanguageTag().getLocale( );
627 if ( rLocale
.Language
== OUString( "fr" ) )
629 bool bFrCA
= rLocale
.Country
== OUString( "CA" );
630 OUString allChars
= OUString( ":;?!%" );
631 OUString
chars( allChars
);
633 chars
= OUString( ":" );
635 sal_Unicode cChar
= rTxt
.GetChar( nEndPos
);
636 bool bHasSpace
= chars
.indexOf( cChar
) != -1;
637 bool bIsSpecial
= allChars
.indexOf( cChar
) != -1;
640 // Get the last word delimiter position
641 xub_StrLen nSttWdPos
= nEndPos
;
642 bool bWasWordDelim
= false;
643 while( nSttWdPos
&& !(bWasWordDelim
= IsWordDelim( rTxt
.GetChar( --nSttWdPos
))))
646 if(INetURLObject::CompareProtocolScheme(rTxt
.Copy(nSttWdPos
+ (bWasWordDelim
? 1 : 0), nEndPos
- nSttWdPos
+ 1)) != INET_PROT_NOT_VALID
) {
651 // Check the presence of "://" in the word
652 xub_StrLen nStrPos
= rTxt
.Search( OUString( "://" ), nSttWdPos
+ 1 );
653 if ( STRING_NOTFOUND
== nStrPos
&& nEndPos
> 0 )
655 // Check the previous char
656 sal_Unicode cPrevChar
= rTxt
.GetChar( nEndPos
- 1 );
657 if ( ( chars
.indexOf( cPrevChar
) == -1 ) && cPrevChar
!= '\t' )
659 // Remove any previous normal space
660 xub_StrLen nPos
= nEndPos
- 1;
661 while ( cPrevChar
== ' ' || cPrevChar
== cNonBreakingSpace
)
663 if ( nPos
== 0 ) break;
665 cPrevChar
= rTxt
.GetChar( nPos
);
669 if ( nEndPos
- nPos
> 0 )
670 rDoc
.Delete( nPos
, nEndPos
);
672 // Add the non-breaking space at the end pos
674 rDoc
.Insert( nPos
, OUString(cNonBreakingSpace
) );
678 else if ( chars
.indexOf( cPrevChar
) != -1 )
682 else if ( cChar
== '/' && nEndPos
> 1 && rTxt
.Len() > (nEndPos
- 1) )
684 // Remove the hardspace right before to avoid formatting URLs
685 sal_Unicode cPrevChar
= rTxt
.GetChar( nEndPos
- 1 );
686 sal_Unicode cMaybeSpaceChar
= rTxt
.GetChar( nEndPos
- 2 );
687 if ( cPrevChar
== ':' && cMaybeSpaceChar
== cNonBreakingSpace
)
689 rDoc
.Delete( nEndPos
- 2, nEndPos
- 1 );
702 sal_Bool
SvxAutoCorrect::FnSetINetAttr( SvxAutoCorrDoc
& rDoc
, const String
& rTxt
,
703 xub_StrLen nSttPos
, xub_StrLen nEndPos
,
706 sal_Int32
nStart(nSttPos
);
707 sal_Int32
nEnd(nEndPos
);
709 String
sURL( URIHelper::FindFirstURLInText( rTxt
, nStart
, nEnd
,
710 GetCharClass( eLang
) ));
711 nSttPos
= (xub_StrLen
)nStart
;
712 nEndPos
= (xub_StrLen
)nEnd
;
713 sal_Bool bRet
= 0 != sURL
.Len();
714 if( bRet
) // also Attribut setzen:
715 rDoc
.SetINetAttr( nSttPos
, nEndPos
, sURL
);
720 sal_Bool
SvxAutoCorrect::FnChgWeightUnderl( SvxAutoCorrDoc
& rDoc
, const String
& rTxt
,
721 xub_StrLen
, xub_StrLen nEndPos
,
725 // at the beginning: _ or * after Space with the folloeing !Space
726 // at the end: _ or * before Space (word delimiter?)
728 sal_Unicode c
, cInsChar
= rTxt
.GetChar( nEndPos
); // underline or bold
729 if( ++nEndPos
!= rTxt
.Len() &&
730 !IsWordDelim( rTxt
.GetChar( nEndPos
) ) )
735 sal_Bool bAlphaNum
= sal_False
;
736 xub_StrLen nPos
= nEndPos
, nFndPos
= STRING_NOTFOUND
;
737 CharClass
& rCC
= GetCharClass( eLang
);
741 switch( c
= rTxt
.GetChar( --nPos
) )
747 if( bAlphaNum
&& nPos
+1 < nEndPos
&& ( !nPos
||
748 IsWordDelim( rTxt
.GetChar( nPos
-1 ))) &&
749 !IsWordDelim( rTxt
.GetChar( nPos
+1 )))
752 // Condition is not satisfied, so cancel
753 nFndPos
= STRING_NOTFOUND
;
759 bAlphaNum
= rCC
.isLetterNumeric( rTxt
, nPos
);
763 if( STRING_NOTFOUND
!= nFndPos
)
765 // first delete the Character at the end - this allows insertion
766 // of an empty hint in SetAttr which would be removed by Delete
767 // (fdo#62536, AUTOFMT in Writer)
768 rDoc
.Delete( nEndPos
, nEndPos
+ 1 );
769 rDoc
.Delete( nFndPos
, nFndPos
+ 1 );
770 // Span the Attribute over the area
772 if( '*' == cInsChar
) // Bold
774 SvxWeightItem
aSvxWeightItem( WEIGHT_BOLD
, SID_ATTR_CHAR_WEIGHT
);
775 rDoc
.SetAttr( nFndPos
, nEndPos
- 1,
776 SID_ATTR_CHAR_WEIGHT
,
781 SvxUnderlineItem
aSvxUnderlineItem( UNDERLINE_SINGLE
, SID_ATTR_CHAR_UNDERLINE
);
782 rDoc
.SetAttr( nFndPos
, nEndPos
- 1,
783 SID_ATTR_CHAR_UNDERLINE
,
788 return STRING_NOTFOUND
!= nFndPos
;
792 sal_Bool
SvxAutoCorrect::FnCptlSttSntnc( SvxAutoCorrDoc
& rDoc
,
793 const String
& rTxt
, sal_Bool bNormalPos
,
794 xub_StrLen nSttPos
, xub_StrLen nEndPos
,
798 if( !rTxt
.Len() || nEndPos
<= nSttPos
)
801 CharClass
& rCC
= GetCharClass( eLang
);
802 String
aText( rTxt
);
803 const sal_Unicode
*pStart
= aText
.GetBuffer(),
804 *pStr
= pStart
+ nEndPos
,
808 sal_Bool bAtStart
= sal_False
;
812 aText
, sal::static_int_cast
< xub_StrLen
>( pStr
- pStart
) ) )
821 sal::static_int_cast
< xub_StrLen
>( pStr
- pStart
) ) )
823 if( lcl_IsInAsciiArr( sImplWordChars
, *pStr
) &&
824 pWordStt
- 1 == pStr
&&
825 // Installation at beginning of paragraph. Replaced < by <= (#i38971#)
826 (long)(pStart
+ 1) <= (long)pStr
&&
829 sal::static_int_cast
< xub_StrLen
>( pStr
-1 - pStart
) ) )
834 } while( 0 == ( bAtStart
= (pStart
== pStr
)) );
838 aText
, sal::static_int_cast
< xub_StrLen
>( pStr
- pStart
) ) ||
840 rCC
.getCharacterType(
842 sal::static_int_cast
< xub_StrLen
>( pWordStt
- pStart
) ) ) ||
843 INetURLObject::CompareProtocolScheme(rTxt
.Copy(pWordStt
- pStart
, pDelim
- pWordStt
+ 1)) != INET_PROT_NOT_VALID
||
844 0x1 == *pWordStt
|| 0x2 == *pWordStt
)
845 return sal_False
; // no character to be replaced, or already ok
847 if( *pDelim
&& 2 >= pDelim
- pWordStt
&&
848 lcl_IsInAsciiArr( ".-)>", *pDelim
) )
851 if( !bAtStart
) // Still no beginning of a paragraph?
853 if ( IsWordDelim( *pStr
) )
855 while( 0 == ( bAtStart
= (pStart
== pStr
--) ) && IsWordDelim( *pStr
))
858 // Asian full stop, full width full stop, full width exclamation mark
859 // and full width question marks are treated as word delimiters
860 else if ( 0x3002 != *pStr
&& 0xFF0E != *pStr
&& 0xFF01 != *pStr
&&
862 return sal_False
; // no valid separator -> no replacement
865 if( bAtStart
) // at the beginning of a paragraph?
867 // Check out the previous paragraph, if it exists.
868 // If so, then check to paragraph separator at the end.
869 const String
* pPrevPara
= rDoc
.GetPrevPara( bNormalPos
);
872 // valid separator -> replace
873 OUString
sChar( *pWordStt
);
874 sChar
= rCC
.titlecase(sChar
); //see fdo#56740
875 return !comphelper::string::equals(sChar
, *pWordStt
) &&
876 rDoc
.ReplaceRange( xub_StrLen( pWordStt
- pStart
), 1, sChar
);
880 bAtStart
= sal_False
;
881 pStart
= aText
.GetBuffer();
882 pStr
= pStart
+ aText
.Len();
884 do { // overwrite all blanks
886 if( !IsWordDelim( *pStr
))
888 } while( 0 == ( bAtStart
= (pStart
== pStr
)) );
891 return sal_False
; // no valid separator -> no replacement
894 // Found [ \t]+[A-Z0-9]+ until here. Test now on the paragraph separator.
895 // all three can happen, but not more than once!
896 const sal_Unicode
* pExceptStt
= 0;
899 sal_Bool bWeiter
= sal_True
;
904 // Western and Asian full stop
909 if (pStr
>= pStart
+ 2 && *(pStr
-2) == '.')
911 //e.g. text "f.o.o. word": Now currently considering
912 //capitalizing word but second last character of
913 //previous word is a . So probably last word is an
914 //anagram that ends in . and not truly the end of a
915 //previous sentence, so don't autocapitalize this word
918 if( nFlag
& C_FULL_STOP
)
919 return sal_False
; // no valid separator -> no replacement
920 nFlag
|= C_FULL_STOP
;
927 if( nFlag
& C_EXCLAMATION_MARK
)
928 return sal_False
; // no valid separator -> no replacement
929 nFlag
|= C_EXCLAMATION_MARK
;
935 if( nFlag
& C_QUESTION_MARK
)
936 return sal_False
; // no valid separator -> no replacement
937 nFlag
|= C_QUESTION_MARK
;
942 return sal_False
; // no valid separator -> no replacement
948 if( bWeiter
&& pStr
-- == pStart
)
950 return sal_False
; // no valid separator -> no replacement
953 if( C_FULL_STOP
!= nFlag
)
957 if( 2 > ( pStr
- pStart
) )
960 if( !rCC
.isLetterNumeric(
961 aText
, sal::static_int_cast
< xub_StrLen
>( pStr
-- - pStart
) ) )
963 sal_Bool bValid
= sal_False
, bAlphaFnd
= sal_False
;
964 const sal_Unicode
* pTmpStr
= pStr
;
969 sal::static_int_cast
< xub_StrLen
>( pTmpStr
- pStart
) ) )
974 else if( rCC
.isLetter(
976 sal::static_int_cast
< xub_StrLen
>(
977 pTmpStr
- pStart
) ) )
985 bAlphaFnd
= sal_True
;
987 else if( bAlphaFnd
|| IsWordDelim( *pTmpStr
) )
990 if( pTmpStr
== pStart
)
997 return sal_False
; // no valid separator -> no replacement
1000 sal_Bool bNumericOnly
= '0' <= *(pStr
+1) && *(pStr
+1) <= '9';
1002 // Search for the beginning of the word
1003 while( !IsWordDelim( *pStr
))
1007 aText
, sal::static_int_cast
< xub_StrLen
>( pStr
- pStart
) ) )
1008 bNumericOnly
= sal_False
;
1010 if( pStart
== pStr
)
1016 if( bNumericOnly
) // consists of only numbers, then not
1019 if( IsWordDelim( *pStr
))
1024 // check on the basis of the exception list
1027 sWord
= OUString(pStr
, pExceptStt
- pStr
+ 1);
1028 if( FindInCplSttExceptList(eLang
, sWord
) )
1031 // Delete all non alphanumeric. Test the characters at the
1032 // beginning/end of the word ( recognizes: "(min.", "/min.", and so on.)
1033 String
sTmp( sWord
);
1034 while( sTmp
.Len() &&
1035 !rCC
.isLetterNumeric( sTmp
, 0 ) )
1038 // Remove all non alphanumeric characters towards the end up until
1040 xub_StrLen nLen
= sTmp
.Len();
1041 while( nLen
&& !rCC
.isLetterNumeric( sTmp
, nLen
-1 ) )
1043 if( nLen
+ 1 < sTmp
.Len() )
1044 sTmp
.Erase( nLen
+ 1 );
1046 if( sTmp
.Len() && sTmp
.Len() != sWord
.Len() &&
1047 FindInCplSttExceptList(eLang
, sTmp
))
1050 if(FindInCplSttExceptList(eLang
, sWord
, sal_True
))
1055 sal_Unicode cSave
= *pWordStt
;
1056 nSttPos
= sal::static_int_cast
< xub_StrLen
>( pWordStt
- rTxt
.GetBuffer() );
1057 OUString
sChar( cSave
);
1058 sChar
= rCC
.titlecase(sChar
); //see fdo#56740
1059 sal_Bool bRet
= sChar
[0] != cSave
&& rDoc
.ReplaceRange( nSttPos
, 1, sChar
);
1061 // Parahaps someone wants to have the word
1062 if( bRet
&& SaveWordCplSttLst
& nFlags
)
1063 rDoc
.SaveCpltSttWord( CptlSttSntnc
, nSttPos
, sWord
, cSave
);
1068 bool SvxAutoCorrect::FnCorrectCapsLock( SvxAutoCorrDoc
& rDoc
, const String
& rTxt
,
1069 xub_StrLen nSttPos
, xub_StrLen nEndPos
,
1070 LanguageType eLang
)
1072 if (nEndPos
- nSttPos
< 2)
1073 // string must be at least 2-character long.
1076 CharClass
& rCC
= GetCharClass( eLang
);
1078 // Check the first 2 letters.
1079 if ( !IsLowerLetter(rCC
.getCharacterType(rTxt
, nSttPos
)) )
1082 if ( !IsUpperLetter(rCC
.getCharacterType(rTxt
, nSttPos
+1)) )
1086 aConverted
.Append( rCC
.uppercase(OUString(rTxt
.GetChar(nSttPos
))) );
1087 aConverted
.Append( rCC
.lowercase(OUString(rTxt
.GetChar(nSttPos
+1))) );
1089 for (xub_StrLen i
= nSttPos
+2; i
< nEndPos
; ++i
)
1091 if ( IsLowerLetter(rCC
.getCharacterType(rTxt
, i
)) )
1092 // A lowercase letter disqualifies the whole text.
1095 if ( IsUpperLetter(rCC
.getCharacterType(rTxt
, i
)) )
1096 // Another uppercase letter. Convert it.
1097 aConverted
.Append(rCC
.lowercase(OUString(rTxt
.GetChar(i
))));
1099 // This is not an alphabetic letter. Leave it as-is.
1100 aConverted
.Append(rTxt
.GetChar(i
));
1103 // Replace the word.
1104 rDoc
.Delete(nSttPos
, nEndPos
);
1105 rDoc
.Insert(nSttPos
, aConverted
);
1111 sal_Unicode
SvxAutoCorrect::GetQuote( sal_Unicode cInsChar
, sal_Bool bSttQuote
,
1112 LanguageType eLang
) const
1114 sal_Unicode cRet
= bSttQuote
? ( '\"' == cInsChar
1115 ? GetStartDoubleQuote()
1116 : GetStartSingleQuote() )
1117 : ( '\"' == cInsChar
1118 ? GetEndDoubleQuote()
1119 : GetEndSingleQuote() );
1122 // then through the Language find the right character
1123 if( LANGUAGE_NONE
== eLang
)
1127 LocaleDataWrapper
& rLcl
= GetLocaleDataWrapper( eLang
);
1128 String
sRet( bSttQuote
1129 ? ( '\"' == cInsChar
1130 ? rLcl
.getDoubleQuotationMarkStart()
1131 : rLcl
.getQuotationMarkStart() )
1132 : ( '\"' == cInsChar
1133 ? rLcl
.getDoubleQuotationMarkEnd()
1134 : rLcl
.getQuotationMarkEnd() ));
1135 cRet
= sRet
.Len() ? sRet
.GetChar( 0 ) : cInsChar
;
1141 void SvxAutoCorrect::InsertQuote( SvxAutoCorrDoc
& rDoc
, xub_StrLen nInsPos
,
1142 sal_Unicode cInsChar
, sal_Bool bSttQuote
,
1145 LanguageType eLang
= rDoc
.GetLanguage( nInsPos
, sal_False
);
1146 sal_Unicode cRet
= GetQuote( cInsChar
, bSttQuote
, eLang
);
1148 OUString
sChg( cInsChar
);
1150 rDoc
.Insert( nInsPos
, sChg
);
1152 rDoc
.Replace( nInsPos
, sChg
);
1154 sChg
= OUString(cRet
);
1156 if( '\"' == cInsChar
)
1158 if( LANGUAGE_SYSTEM
== eLang
)
1159 eLang
= GetAppLang().getLanguageType();
1162 case LANGUAGE_FRENCH
:
1163 case LANGUAGE_FRENCH_BELGIAN
:
1164 case LANGUAGE_FRENCH_CANADIAN
:
1165 case LANGUAGE_FRENCH_SWISS
:
1166 case LANGUAGE_FRENCH_LUXEMBOURG
:
1168 OUString
s( cNonBreakingSpace
);
1169 // UNICODE code for no break space
1170 if( rDoc
.Insert( bSttQuote
? nInsPos
+1 : nInsPos
, s
))
1180 rDoc
.Replace( nInsPos
, sChg
);
1183 String
SvxAutoCorrect::GetQuote( SvxAutoCorrDoc
& rDoc
, xub_StrLen nInsPos
,
1184 sal_Unicode cInsChar
, sal_Bool bSttQuote
)
1186 LanguageType eLang
= rDoc
.GetLanguage( nInsPos
, sal_False
);
1187 sal_Unicode cRet
= GetQuote( cInsChar
, bSttQuote
, eLang
);
1189 String sRet
= OUString(cRet
);
1191 if( '\"' == cInsChar
)
1193 if( LANGUAGE_SYSTEM
== eLang
)
1194 eLang
= GetAppLang().getLanguageType();
1197 case LANGUAGE_FRENCH
:
1198 case LANGUAGE_FRENCH_BELGIAN
:
1199 case LANGUAGE_FRENCH_CANADIAN
:
1200 case LANGUAGE_FRENCH_SWISS
:
1201 case LANGUAGE_FRENCH_LUXEMBOURG
:
1205 sRet
.Insert( ' ', 0 );
1213 SvxAutoCorrect::DoAutoCorrect( SvxAutoCorrDoc
& rDoc
, const String
& rTxt
,
1214 xub_StrLen nInsPos
, sal_Unicode cChar
,
1215 sal_Bool bInsert
, Window
* pFrameWin
)
1218 bool bIsNextRun
= bRunNext
;
1219 bRunNext
= false; // if it was set, then it has to be turned off
1221 do{ // only for middle check loop !!
1224 // Prevent double space
1225 if( nInsPos
&& ' ' == cChar
&&
1226 IsAutoCorrFlag( IgnoreDoubleSpace
) &&
1227 ' ' == rTxt
.GetChar( nInsPos
- 1 ) )
1229 nRet
= IgnoreDoubleSpace
;
1233 sal_Bool bSingle
= '\'' == cChar
;
1234 sal_Bool bIsReplaceQuote
=
1235 (IsAutoCorrFlag( ChgQuotes
) && ('\"' == cChar
)) ||
1236 (IsAutoCorrFlag( ChgSglQuotes
) && bSingle
);
1237 if( bIsReplaceQuote
)
1240 sal_Bool bSttQuote
= !nInsPos
||
1241 IsWordDelim( ( cPrev
= rTxt
.GetChar( nInsPos
-1 ))) ||
1242 lcl_IsInAsciiArr( "([{", cPrev
) ||
1243 ( cEmDash
&& cEmDash
== cPrev
) ||
1244 ( cEnDash
&& cEnDash
== cPrev
);
1246 InsertQuote( rDoc
, nInsPos
, cChar
, bSttQuote
, bInsert
);
1247 nRet
= bSingle
? ChgSglQuotes
: ChgQuotes
;
1252 rDoc
.Insert( nInsPos
, OUString(cChar
) );
1254 rDoc
.Replace( nInsPos
, OUString(cChar
) );
1256 // Hardspaces autocorrection
1257 if ( IsAutoCorrFlag( AddNonBrkSpace
) )
1259 if ( NeedsHardspaceAutocorr( cChar
) &&
1260 FnAddNonBrkSpace( rDoc
, rTxt
, 0, nInsPos
, rDoc
.GetLanguage( nInsPos
, sal_False
) ) )
1262 nRet
= AddNonBrkSpace
;
1264 else if ( bIsNextRun
&& !IsAutoCorrectChar( cChar
) )
1266 // Remove the NBSP if it wasn't an autocorrection
1267 if ( nInsPos
!= 0 && NeedsHardspaceAutocorr( rTxt
.GetChar( nInsPos
- 1 ) ) &&
1268 cChar
!= ' ' && cChar
!= '\t' && cChar
!= cNonBreakingSpace
)
1270 // Look for the last HARD_SPACE
1271 xub_StrLen nPos
= nInsPos
- 1;
1272 bool bContinue
= true;
1275 const sal_Unicode cTmpChar
= rTxt
.GetChar( nPos
);
1276 if ( cTmpChar
== cNonBreakingSpace
)
1278 rDoc
.Delete( nPos
, nPos
+ 1 );
1279 nRet
= AddNonBrkSpace
;
1282 else if ( !NeedsHardspaceAutocorr( cTmpChar
) || nPos
== 0 )
1294 xub_StrLen nPos
= nInsPos
- 1;
1296 if( IsWordDelim( rTxt
.GetChar( nPos
)))
1299 // Set bold or underline automatically?
1300 if( '*' == cChar
|| '_' == cChar
)
1302 if( IsAutoCorrFlag( ChgWeightUnderl
) &&
1303 FnChgWeightUnderl( rDoc
, rTxt
, 0, nPos
+1 ) )
1304 nRet
= ChgWeightUnderl
;
1308 while( nPos
&& !IsWordDelim( rTxt
.GetChar( --nPos
)))
1311 // Found a Paragraph-start or a Blank, search for the word shortcut in
1313 xub_StrLen nCapLttrPos
= nPos
+1; // on the 1st Character
1314 if( !nPos
&& !IsWordDelim( rTxt
.GetChar( 0 )))
1315 --nCapLttrPos
; // Absatz Anfang und kein Blank !
1317 LanguageType eLang
= rDoc
.GetLanguage( nCapLttrPos
, sal_False
);
1318 if( LANGUAGE_SYSTEM
== eLang
)
1319 eLang
= MsLangId::getSystemLanguage();
1320 CharClass
& rCC
= GetCharClass( eLang
);
1322 // no symbol characters
1323 if( lcl_IsSymbolChar( rCC
, rTxt
, nCapLttrPos
, nInsPos
))
1326 if( IsAutoCorrFlag( Autocorrect
) )
1328 const String
* pPara
= 0;
1329 const String
** ppPara
= IsAutoCorrFlag(CptlSttSntnc
) ? &pPara
: 0;
1331 sal_Bool bChgWord
= rDoc
.ChgAutoCorrWord( nCapLttrPos
, nInsPos
,
1333 // since LibO 4.1, '-' is a word separator
1334 // fdo#67742 avoid "--" to be replaced by "–" if next is "-"
1335 if( rTxt
.Len() >= 3 &&
1336 rTxt
.Equals( String("---"), rTxt
.Len()-3, 3 ) )
1340 xub_StrLen nCapLttrPos1
= nCapLttrPos
, nInsPos1
= nInsPos
;
1341 while( nCapLttrPos1
< nInsPos
&&
1342 lcl_IsInAsciiArr( sImplSttSkipChars
, rTxt
.GetChar( nCapLttrPos1
) )
1345 while( nCapLttrPos1
< nInsPos1
&& nInsPos1
&&
1346 lcl_IsInAsciiArr( sImplEndSkipChars
, rTxt
.GetChar( nInsPos1
-1 ) )
1350 if( (nCapLttrPos1
!= nCapLttrPos
|| nInsPos1
!= nInsPos
) &&
1351 nCapLttrPos1
< nInsPos1
&&
1352 rDoc
.ChgAutoCorrWord( nCapLttrPos1
, nInsPos1
, *this, ppPara
))
1354 bChgWord
= sal_True
;
1355 nCapLttrPos
= nCapLttrPos1
;
1364 xub_StrLen nEnd
= nCapLttrPos
;
1365 while( nEnd
< pPara
->Len() &&
1366 !IsWordDelim( pPara
->GetChar( nEnd
)))
1369 // Capital letter at beginning of paragraph?
1370 if( IsAutoCorrFlag( CptlSttSntnc
) &&
1371 FnCptlSttSntnc( rDoc
, *pPara
, sal_False
,
1372 nCapLttrPos
, nEnd
, eLang
) )
1373 nRet
|= CptlSttSntnc
;
1375 if( IsAutoCorrFlag( ChgToEnEmDash
) &&
1376 FnChgToEnEmDash( rDoc
, rTxt
, nCapLttrPos
, nEnd
, eLang
) )
1377 nRet
|= ChgToEnEmDash
;
1383 if( ( IsAutoCorrFlag( nRet
= ChgOrdinalNumber
) &&
1384 (nInsPos
>= 2 ) && // fdo#69762 avoid autocorrect for 2e-3
1385 ( '-' != cChar
|| 'E' != toupper(rTxt
.GetChar(nInsPos
-1)) ||
1386 '0' > rTxt
.GetChar(nInsPos
-2) || '9' < rTxt
.GetChar(nInsPos
-2) ) &&
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
) ) )
1394 bool bLockKeyOn
= pFrameWin
&& (pFrameWin
->GetIndicatorState() & INDICATOR_CAPSLOCK
);
1395 bool bUnsupported
= lcl_IsUnsupportedUnicodeChar( rCC
, rTxt
, nCapLttrPos
, nInsPos
);
1398 if ( bLockKeyOn
&& IsAutoCorrFlag( CorrectCapsLock
) &&
1399 FnCorrectCapsLock( rDoc
, rTxt
, nCapLttrPos
, nInsPos
, eLang
) )
1401 // Correct accidental use of cAPS LOCK key (do this only when
1402 // the caps or shift lock key is pressed). Turn off the caps
1404 nRet
|= CorrectCapsLock
;
1405 pFrameWin
->SimulateKeyPress( KEY_CAPSLOCK
);
1408 // Capital letter at beginning of paragraph ?
1409 if( !bUnsupported
&&
1410 IsAutoCorrFlag( CptlSttSntnc
) &&
1411 FnCptlSttSntnc( rDoc
, rTxt
, sal_True
, nCapLttrPos
, nInsPos
, eLang
) )
1412 nRet
|= CptlSttSntnc
;
1414 // Two capital letters at beginning of word ??
1415 if( !bUnsupported
&&
1416 IsAutoCorrFlag( CptlSttWrd
) &&
1417 FnCptlSttWrd( rDoc
, rTxt
, nCapLttrPos
, nInsPos
, eLang
) )
1420 if( IsAutoCorrFlag( ChgToEnEmDash
) &&
1421 FnChgToEnEmDash( rDoc
, rTxt
, nCapLttrPos
, nInsPos
, eLang
) )
1422 nRet
|= ChgToEnEmDash
;
1430 SvxAutoCorrectLanguageLists
& SvxAutoCorrect::_GetLanguageList(
1431 LanguageType eLang
)
1433 if(pLangTable
->find(eLang
) == pLangTable
->end())
1434 CreateLanguageFile(eLang
, sal_True
);
1435 return *(pLangTable
->find(eLang
)->second
);
1438 void SvxAutoCorrect::SaveCplSttExceptList( LanguageType eLang
)
1440 boost::ptr_map
<LanguageType
, SvxAutoCorrectLanguageLists
>::iterator nTmpVal
= pLangTable
->find(eLang
);
1441 if(nTmpVal
!= pLangTable
->end() && nTmpVal
->second
)
1442 nTmpVal
->second
->SaveCplSttExceptList();
1446 OSL_FAIL("Save an empty list? ");
1451 void SvxAutoCorrect::SaveWrdSttExceptList(LanguageType eLang
)
1453 boost::ptr_map
<LanguageType
, SvxAutoCorrectLanguageLists
>::iterator nTmpVal
= pLangTable
->find(eLang
);
1454 if(nTmpVal
!= pLangTable
->end() && nTmpVal
->second
)
1455 nTmpVal
->second
->SaveWrdSttExceptList();
1459 OSL_FAIL("Save an empty list? ");
1464 // Adds a single word. The list will immediately be written to the file!
1465 sal_Bool
SvxAutoCorrect::AddCplSttException( const String
& rNew
,
1466 LanguageType eLang
)
1468 SvxAutoCorrectLanguageLists
* pLists
= 0;
1469 // either the right language is present or it will be this in the general list
1470 boost::ptr_map
<LanguageType
, SvxAutoCorrectLanguageLists
>::iterator nTmpVal
= pLangTable
->find(eLang
);
1471 if(nTmpVal
!= pLangTable
->end())
1472 pLists
= nTmpVal
->second
;
1475 nTmpVal
= pLangTable
->find(LANGUAGE_UNDETERMINED
);
1476 if(nTmpVal
!= pLangTable
->end())
1477 pLists
= nTmpVal
->second
;
1478 else if(CreateLanguageFile(LANGUAGE_UNDETERMINED
, sal_True
))
1479 pLists
= pLangTable
->find(LANGUAGE_UNDETERMINED
)->second
;
1481 OSL_ENSURE(pLists
, "No auto correction data");
1482 return pLists
->AddToCplSttExceptList(rNew
);
1485 // Adds a single word. The list will immediately be written to the file!
1486 sal_Bool
SvxAutoCorrect::AddWrtSttException( const String
& rNew
,
1487 LanguageType eLang
)
1489 SvxAutoCorrectLanguageLists
* pLists
= 0;
1490 //either the right language is present or it is set in the general list
1491 boost::ptr_map
<LanguageType
, SvxAutoCorrectLanguageLists
>::iterator nTmpVal
= pLangTable
->find(eLang
);
1492 if(nTmpVal
!= pLangTable
->end())
1493 pLists
= nTmpVal
->second
;
1496 nTmpVal
= pLangTable
->find(LANGUAGE_UNDETERMINED
);
1497 if(nTmpVal
!= pLangTable
->end())
1498 pLists
= nTmpVal
->second
;
1499 else if(CreateLanguageFile(LANGUAGE_UNDETERMINED
, sal_True
))
1500 pLists
= pLangTable
->find(LANGUAGE_UNDETERMINED
)->second
;
1502 OSL_ENSURE(pLists
, "No auto correction file!");
1503 return pLists
->AddToWrdSttExceptList(rNew
);
1506 sal_Bool
SvxAutoCorrect::GetPrevAutoCorrWord( SvxAutoCorrDoc
& rDoc
,
1507 const String
& rTxt
, xub_StrLen nPos
,
1508 String
& rWord
) const
1513 xub_StrLen nEnde
= nPos
;
1515 // it must be followed by a blank or tab!
1516 if( ( nPos
< rTxt
.Len() &&
1517 !IsWordDelim( rTxt
.GetChar( nPos
))) ||
1518 IsWordDelim( rTxt
.GetChar( --nPos
)))
1521 while( nPos
&& !IsWordDelim( rTxt
.GetChar( --nPos
)))
1524 // Found a Paragraph-start or a Blank, search for the word shortcut in
1526 xub_StrLen nCapLttrPos
= nPos
+1; // on the 1st Character
1527 if( !nPos
&& !IsWordDelim( rTxt
.GetChar( 0 )))
1528 --nCapLttrPos
; // Beginning of pargraph and no Blank!
1530 while( lcl_IsInAsciiArr( sImplSttSkipChars
, rTxt
.GetChar( nCapLttrPos
)) )
1531 if( ++nCapLttrPos
>= nEnde
)
1534 if( 3 > nEnde
- nCapLttrPos
)
1537 LanguageType eLang
= rDoc
.GetLanguage( nCapLttrPos
, sal_False
);
1538 if( LANGUAGE_SYSTEM
== eLang
)
1539 eLang
= MsLangId::getSystemLanguage();
1541 SvxAutoCorrect
* pThis
= (SvxAutoCorrect
*)this;
1542 CharClass
& rCC
= pThis
->GetCharClass( eLang
);
1544 if( lcl_IsSymbolChar( rCC
, rTxt
, nCapLttrPos
, nEnde
))
1547 rWord
= rTxt
.Copy( nCapLttrPos
, nEnde
- nCapLttrPos
);
1551 sal_Bool
SvxAutoCorrect::CreateLanguageFile( LanguageType eLang
, sal_Bool bNewFile
)
1553 OSL_ENSURE(pLangTable
->find(eLang
) == pLangTable
->end(), "Language already exists ");
1555 OUString
sUserDirFile( GetAutoCorrFileName( eLang
, sal_True
, sal_False
));
1556 OUString
sShareDirFile( sUserDirFile
);
1558 SvxAutoCorrectLanguageListsPtr pLists
= 0;
1560 Time
nMinTime( 0, 2 ), nAktTime( Time::SYSTEM
), nLastCheckTime( Time::EMPTY
);
1562 std::map
<LanguageType
, long>::iterator nFndPos
= aLastFileTable
.find(eLang
);
1563 if(nFndPos
!= aLastFileTable
.end() &&
1564 (nLastCheckTime
.SetTime(nFndPos
->second
), nLastCheckTime
< nAktTime
) &&
1565 nAktTime
- nLastCheckTime
< nMinTime
)
1567 // no need to test the file, because the last check is not older then
1571 sShareDirFile
= sUserDirFile
;
1572 pLists
= new SvxAutoCorrectLanguageLists( *this, sShareDirFile
, sUserDirFile
);
1573 pLangTable
->insert(eLang
, pLists
);
1574 aLastFileTable
.erase(nFndPos
);
1577 else if( ( FStatHelper::IsDocument( sUserDirFile
) ||
1578 FStatHelper::IsDocument( sShareDirFile
=
1579 GetAutoCorrFileName( eLang
, sal_False
, sal_False
) ) ) ||
1580 ( sShareDirFile
= sUserDirFile
, bNewFile
))
1582 pLists
= new SvxAutoCorrectLanguageLists( *this, sShareDirFile
, sUserDirFile
);
1583 pLangTable
->insert(eLang
, pLists
);
1584 if (nFndPos
!= aLastFileTable
.end())
1585 aLastFileTable
.erase(nFndPos
);
1587 else if( !bNewFile
)
1589 aLastFileTable
[eLang
] = nAktTime
.GetTime();
1594 sal_Bool
SvxAutoCorrect::PutText( const String
& rShort
, const String
& rLong
,
1595 LanguageType eLang
)
1597 boost::ptr_map
<LanguageType
, SvxAutoCorrectLanguageLists
>::iterator nTmpVal
= pLangTable
->find(eLang
);
1598 if(nTmpVal
!= pLangTable
->end())
1599 return nTmpVal
->second
->PutText(rShort
, rLong
);
1600 if(CreateLanguageFile(eLang
))
1601 return pLangTable
->find(eLang
)->second
->PutText(rShort
, rLong
);
1605 sal_Bool
SvxAutoCorrect::MakeCombinedChanges( std::vector
<SvxAutocorrWord
>& aNewEntries
,
1606 std::vector
<SvxAutocorrWord
>& aDeleteEntries
,
1607 LanguageType eLang
)
1609 boost::ptr_map
<LanguageType
, SvxAutoCorrectLanguageLists
>::iterator nTmpVal
= pLangTable
->find(eLang
);
1610 if(nTmpVal
!= pLangTable
->end())
1612 return nTmpVal
->second
->MakeCombinedChanges( aNewEntries
, aDeleteEntries
);
1614 else if(CreateLanguageFile( eLang
))
1616 return pLangTable
->find( eLang
)->second
->MakeCombinedChanges( aNewEntries
, aDeleteEntries
);
1623 // - return the replacement text (only for SWG-Format, all other
1624 // can be taken from the word list!)
1625 sal_Bool
SvxAutoCorrect::GetLongText( const com::sun::star::uno::Reference
< com::sun::star::embed::XStorage
>&, const String
&, const String
& , String
& )
1630 // Text with attribution (only the SWG - SWG format!)
1631 sal_Bool
SvxAutoCorrect::PutText( const com::sun::star::uno::Reference
< com::sun::star::embed::XStorage
>&, const String
&, const String
&, SfxObjectShell
&,
1637 void EncryptBlockName_Imp( String
& rName
)
1639 xub_StrLen nLen
, nPos
= 1;
1640 rName
.Insert( '#', 0 );
1641 sal_Unicode
* pName
= rName
.GetBufferAccess();
1642 for ( nLen
= rName
.Len(), ++pName
; nPos
< nLen
; ++nPos
, ++pName
)
1644 if( lcl_IsInAsciiArr( "!/:.\\", *pName
))
1649 /* This code is copied from SwXMLTextBlocks::GeneratePackageName */
1650 static void GeneratePackageName ( const String
& rShort
, String
& rPackageName
)
1652 rPackageName
= rShort
;
1653 xub_StrLen nPos
= 0;
1654 sal_Unicode pDelims
[] = { '!', '/', ':', '.', '\\', 0 };
1655 OString
sByte(OUStringToOString(rPackageName
, RTL_TEXTENCODING_UTF7
));
1656 rPackageName
= OStringToOUString(sByte
, RTL_TEXTENCODING_ASCII_US
);
1657 while( STRING_NOTFOUND
!= ( nPos
= rPackageName
.SearchChar( pDelims
, nPos
)))
1659 rPackageName
.SetChar( nPos
, '_' );
1664 static const SvxAutocorrWord
* lcl_SearchWordsInList(
1665 SvxAutoCorrectLanguageListsPtr pList
, const String
& rTxt
,
1666 xub_StrLen
& rStt
, xub_StrLen nEndPos
)
1668 const SvxAutocorrWordList
* pAutoCorrWordList
= pList
->GetAutocorrWordList();
1669 return pAutoCorrWordList
->SearchWordsInList( rTxt
, rStt
, nEndPos
);
1672 // the search for the words in the substitution table
1673 const SvxAutocorrWord
* SvxAutoCorrect::SearchWordsInList(
1674 const String
& rTxt
, xub_StrLen
& rStt
, xub_StrLen nEndPos
,
1675 SvxAutoCorrDoc
&, LanguageType
& rLang
)
1677 LanguageType eLang
= rLang
;
1678 const SvxAutocorrWord
* pRet
= 0;
1679 if( LANGUAGE_SYSTEM
== eLang
)
1680 eLang
= MsLangId::getSystemLanguage();
1682 // First search for eLang, then US-English -> English
1683 // and last in LANGUAGE_UNDETERMINED
1684 if(pLangTable
->find(eLang
) != pLangTable
->end() || CreateLanguageFile(eLang
, sal_False
))
1686 //the language is available - so bring it on
1687 SvxAutoCorrectLanguageLists
* pList
= pLangTable
->find(eLang
)->second
;
1688 pRet
= lcl_SearchWordsInList( pList
, rTxt
, rStt
, nEndPos
);
1696 // If it still could not be found here, then keep on searching
1698 LanguageType nTmpKey1
= eLang
& 0x7ff, // the main language in many cases DE
1699 nTmpKey2
= eLang
& 0x3ff; // otherwise for example EN
1700 if(nTmpKey1
!= eLang
&& (pLangTable
->find(nTmpKey1
) != pLangTable
->end() || CreateLanguageFile(nTmpKey1
, sal_False
)))
1702 //the language is available - so bring it on
1703 SvxAutoCorrectLanguageLists
* pList
= pLangTable
->find(nTmpKey1
)->second
;
1704 pRet
= lcl_SearchWordsInList( pList
, rTxt
, rStt
, nEndPos
);
1712 if(nTmpKey2
!= eLang
&& (pLangTable
->find(nTmpKey2
) != pLangTable
->end() || CreateLanguageFile(nTmpKey2
, sal_False
)))
1714 //the language is available - so bring it on
1715 SvxAutoCorrectLanguageLists
* pList
= pLangTable
->find(nTmpKey2
)->second
;
1716 pRet
= lcl_SearchWordsInList( pList
, rTxt
, rStt
, nEndPos
);
1724 if(pLangTable
->find(LANGUAGE_UNDETERMINED
) != pLangTable
->end() || CreateLanguageFile(LANGUAGE_UNDETERMINED
, sal_False
))
1726 //the language is available - so bring it on
1727 SvxAutoCorrectLanguageLists
* pList
= pLangTable
->find(LANGUAGE_UNDETERMINED
)->second
;
1728 pRet
= lcl_SearchWordsInList( pList
, rTxt
, rStt
, nEndPos
);
1731 rLang
= LANGUAGE_UNDETERMINED
;
1738 sal_Bool
SvxAutoCorrect::FindInWrdSttExceptList( LanguageType eLang
,
1739 const String
& sWord
)
1741 // First search for eLang, then US-English -> English
1742 // and last in LANGUAGE_UNDETERMINED
1743 LanguageType nTmpKey1
= eLang
& 0x7ff, // the main language in many cases DE
1744 nTmpKey2
= eLang
& 0x3ff; // otherwise for example EN
1745 String
sTemp(sWord
);
1747 if(pLangTable
->find(eLang
) != pLangTable
->end() || CreateLanguageFile(eLang
, sal_False
))
1749 //the language is available - so bring it on
1750 SvxAutoCorrectLanguageLists
* pList
= pLangTable
->find(eLang
)->second
;
1751 String
_sTemp(sWord
);
1752 if(pList
->GetWrdSttExceptList()->find(&_sTemp
) != pList
->GetWrdSttExceptList()->end() )
1756 // If it still could not be found here, then keep on searching
1757 if(nTmpKey1
!= eLang
&& (pLangTable
->find(nTmpKey1
) != pLangTable
->end() || CreateLanguageFile(nTmpKey1
, sal_False
)))
1759 //the language is available - so bring it on
1760 SvxAutoCorrectLanguageLists
* pList
= pLangTable
->find(nTmpKey1
)->second
;
1761 if(pList
->GetWrdSttExceptList()->find(&sTemp
) != pList
->GetWrdSttExceptList()->end() )
1765 if(nTmpKey2
!= eLang
&& (pLangTable
->find(nTmpKey2
) != pLangTable
->end() || CreateLanguageFile(nTmpKey2
, sal_False
)))
1767 //the language is available - so bring it on
1768 SvxAutoCorrectLanguageLists
* pList
= pLangTable
->find(nTmpKey2
)->second
;
1769 if(pList
->GetWrdSttExceptList()->find(&sTemp
) != pList
->GetWrdSttExceptList()->end() )
1773 if(pLangTable
->find(LANGUAGE_UNDETERMINED
) != pLangTable
->end() || CreateLanguageFile(LANGUAGE_UNDETERMINED
, sal_False
))
1775 //the language is available - so bring it on
1776 SvxAutoCorrectLanguageLists
* pList
= pLangTable
->find(LANGUAGE_UNDETERMINED
)->second
;
1777 if(pList
->GetWrdSttExceptList()->find(&sTemp
) != pList
->GetWrdSttExceptList()->end() )
1783 static sal_Bool
lcl_FindAbbreviation( const SvStringsISortDtor
* pList
, const String
& sWord
)
1785 String
sAbk(OUString('~'));
1786 SvStringsISortDtor::const_iterator it
= pList
->find( &sAbk
);
1787 sal_uInt16 nPos
= it
- pList
->begin();
1788 if( nPos
< pList
->size() )
1790 String
sLowerWord( sWord
); sLowerWord
.ToLowerAscii();
1792 for( sal_uInt16 n
= nPos
;
1793 n
< pList
->size() &&
1794 '~' == ( pAbk
= (*pList
)[ n
])->GetChar( 0 );
1797 // ~ and ~. are not allowed!
1798 if( 2 < pAbk
->Len() && pAbk
->Len() - 1 <= sWord
.Len() )
1800 String
sLowerAbk( *pAbk
); sLowerAbk
.ToLowerAscii();
1801 for( xub_StrLen i
= sLowerAbk
.Len(), ii
= sLowerWord
.Len(); i
; )
1803 if( !--i
) // agrees
1806 if( sLowerAbk
.GetChar( i
) != sLowerWord
.GetChar( --ii
))
1812 OSL_ENSURE( !(nPos
&& '~' == (*pList
)[ --nPos
]->GetChar( 0 ) ),
1813 "Wrongly sorted exception list?" );
1817 sal_Bool
SvxAutoCorrect::FindInCplSttExceptList(LanguageType eLang
,
1818 const String
& sWord
, sal_Bool bAbbreviation
)
1820 // First search for eLang, then US-English -> English
1821 // and last in LANGUAGE_UNDETERMINED
1822 LanguageType nTmpKey1
= eLang
& 0x7ff, // the main language in many cases DE
1823 nTmpKey2
= eLang
& 0x3ff; // otherwise for example EN
1824 String
sTemp( sWord
);
1826 if(pLangTable
->find(eLang
) != pLangTable
->end() || CreateLanguageFile(eLang
, sal_False
))
1828 //the language is available - so bring it on
1829 const SvStringsISortDtor
* pList
= pLangTable
->find(eLang
)->second
->GetCplSttExceptList();
1830 if(bAbbreviation
? lcl_FindAbbreviation(pList
, sWord
) : pList
->find(&sTemp
) != pList
->end() )
1834 // If it still could not be found here, then keep on searching
1835 if(nTmpKey1
!= eLang
&& (pLangTable
->find(nTmpKey1
) != pLangTable
->end() || CreateLanguageFile(nTmpKey1
, sal_False
)))
1837 const SvStringsISortDtor
* pList
= pLangTable
->find(nTmpKey1
)->second
->GetCplSttExceptList();
1838 if(bAbbreviation
? lcl_FindAbbreviation(pList
, sWord
) : pList
->find(&sTemp
) != pList
->end() )
1842 if(nTmpKey2
!= eLang
&& (pLangTable
->find(nTmpKey2
) != pLangTable
->end() || CreateLanguageFile(nTmpKey2
, sal_False
)))
1844 //the language is available - so bring it on
1845 const SvStringsISortDtor
* pList
= pLangTable
->find(nTmpKey2
)->second
->GetCplSttExceptList();
1846 if(bAbbreviation
? lcl_FindAbbreviation(pList
, sWord
) : pList
->find(&sTemp
) != pList
->end() )
1850 if(pLangTable
->find(LANGUAGE_UNDETERMINED
) != pLangTable
->end() || CreateLanguageFile(LANGUAGE_UNDETERMINED
, sal_False
))
1852 //the language is available - so bring it on
1853 const SvStringsISortDtor
* pList
= pLangTable
->find(LANGUAGE_UNDETERMINED
)->second
->GetCplSttExceptList();
1854 if(bAbbreviation
? lcl_FindAbbreviation(pList
, sWord
) : pList
->find(&sTemp
) != pList
->end() )
1860 OUString
SvxAutoCorrect::GetAutoCorrFileName( LanguageType eLang
,
1861 sal_Bool bNewFile
, sal_Bool bTst
) const
1863 OUString sRet
, sExt( LanguageTag( eLang
).getBcp47() );
1865 sExt
= "_" + sExt
+ ".dat";
1867 ( sRet
= sUserAutoCorrFile
) += sExt
;
1869 ( sRet
= sShareAutoCorrFile
) += sExt
;
1872 // test first in the user directory - if not exist, then
1873 ( sRet
= sUserAutoCorrFile
) += sExt
;
1874 if( !FStatHelper::IsDocument( sRet
))
1875 ( sRet
= sShareAutoCorrFile
) += sExt
;
1880 SvxAutoCorrectLanguageLists::SvxAutoCorrectLanguageLists(
1881 SvxAutoCorrect
& rParent
,
1882 const String
& rShareAutoCorrectFile
,
1883 const String
& rUserAutoCorrectFile
)
1884 : sShareAutoCorrFile( rShareAutoCorrectFile
),
1885 sUserAutoCorrFile( rUserAutoCorrectFile
),
1886 aModifiedDate( Date::EMPTY
),
1887 aModifiedTime( Time::EMPTY
),
1888 aLastCheckTime( Time::EMPTY
),
1889 pCplStt_ExcptLst( 0 ),
1890 pWrdStt_ExcptLst( 0 ),
1891 pAutocorr_List( 0 ),
1892 rAutoCorrect(rParent
),
1897 SvxAutoCorrectLanguageLists::~SvxAutoCorrectLanguageLists()
1899 delete pCplStt_ExcptLst
;
1900 delete pWrdStt_ExcptLst
;
1901 delete pAutocorr_List
;
1904 sal_Bool
SvxAutoCorrectLanguageLists::IsFileChanged_Imp()
1906 // Access the file system only every 2 minutes to check the date stamp
1907 sal_Bool bRet
= sal_False
;
1909 Time
nMinTime( 0, 2 );
1910 Time
nAktTime( Time::SYSTEM
);
1911 if( aLastCheckTime
> nAktTime
|| // overflow?
1912 ( nAktTime
-= aLastCheckTime
) > nMinTime
) // min time past
1914 Date
aTstDate( Date::EMPTY
); Time
aTstTime( Time::EMPTY
);
1915 if( FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile
,
1916 &aTstDate
, &aTstTime
) &&
1917 ( aModifiedDate
!= aTstDate
|| aModifiedTime
!= aTstTime
))
1920 // then remove all the lists fast!
1921 if( CplSttLstLoad
& nFlags
&& pCplStt_ExcptLst
)
1922 delete pCplStt_ExcptLst
, pCplStt_ExcptLst
= 0;
1923 if( WrdSttLstLoad
& nFlags
&& pWrdStt_ExcptLst
)
1924 delete pWrdStt_ExcptLst
, pWrdStt_ExcptLst
= 0;
1925 if( ChgWordLstLoad
& nFlags
&& pAutocorr_List
)
1926 delete pAutocorr_List
, pAutocorr_List
= 0;
1927 nFlags
&= ~(CplSttLstLoad
| WrdSttLstLoad
| ChgWordLstLoad
);
1929 aLastCheckTime
= Time( Time::SYSTEM
);
1934 void SvxAutoCorrectLanguageLists::LoadXMLExceptList_Imp(
1935 SvStringsISortDtor
*& rpLst
,
1936 const sal_Char
* pStrmName
,
1937 SotStorageRef
& rStg
)
1940 rpLst
->DeleteAndDestroyAll();
1942 rpLst
= new SvStringsISortDtor
;
1945 String
sStrmName( pStrmName
, RTL_TEXTENCODING_MS_1252
);
1946 String
sTmp( sStrmName
);
1948 if( rStg
.Is() && rStg
->IsStream( sStrmName
) )
1950 SvStorageStreamRef xStrm
= rStg
->OpenSotStream( sTmp
,
1951 ( STREAM_READ
| STREAM_SHARE_DENYWRITE
| STREAM_NOCREATE
) );
1952 if( SVSTREAM_OK
!= xStrm
->GetError())
1956 RemoveStream_Imp( sStrmName
);
1960 uno::Reference
< uno::XComponentContext
> xContext
=
1961 comphelper::getProcessComponentContext();
1963 xml::sax::InputSource aParserInput
;
1964 aParserInput
.sSystemId
= sStrmName
;
1967 xStrm
->SetBufferSize( 8 * 1024 );
1968 aParserInput
.aInputStream
= new utl::OInputStreamWrapper( *xStrm
);
1971 uno::Reference
< xml::sax::XDocumentHandler
> xFilter
= new SvXMLExceptionListImport ( xContext
, *rpLst
);
1973 // connect parser and filter
1974 uno::Reference
< xml::sax::XParser
> xParser
= xml::sax::Parser::create( xContext
);
1975 xParser
->setDocumentHandler( xFilter
);
1980 xParser
->parseStream( aParserInput
);
1982 catch( const xml::sax::SAXParseException
& )
1986 catch( const xml::sax::SAXException
& )
1990 catch( const io::IOException
& )
1998 FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile
,
1999 &aModifiedDate
, &aModifiedTime
);
2000 aLastCheckTime
= Time( Time::SYSTEM
);
2005 void SvxAutoCorrectLanguageLists::SaveExceptList_Imp(
2006 const SvStringsISortDtor
& rLst
,
2007 const sal_Char
* pStrmName
,
2008 SotStorageRef
&rStg
,
2013 String
sStrmName( pStrmName
, RTL_TEXTENCODING_MS_1252
);
2016 rStg
->Remove( sStrmName
);
2021 SotStorageStreamRef xStrm
= rStg
->OpenSotStream( sStrmName
,
2022 ( STREAM_READ
| STREAM_WRITE
| STREAM_SHARE_DENYWRITE
) );
2025 xStrm
->SetSize( 0 );
2026 xStrm
->SetBufferSize( 8192 );
2027 OUString
aMime( "text/xml" );
2030 xStrm
->SetProperty( OUString("MediaType"), aAny
);
2033 uno::Reference
< uno::XComponentContext
> xContext
=
2034 comphelper::getProcessComponentContext();
2036 uno::Reference
< xml::sax::XWriter
> xWriter
= xml::sax::Writer::create(xContext
);
2037 uno::Reference
< io::XOutputStream
> xOut
= new utl::OOutputStreamWrapper( *xStrm
);
2038 xWriter
->setOutputStream(xOut
);
2040 uno::Reference
< xml::sax::XDocumentHandler
> xHandler(xWriter
, UNO_QUERY_THROW
);
2041 SvXMLExceptionListExport
aExp( xContext
, rLst
, sStrmName
, xHandler
);
2043 aExp
.exportDoc( XML_BLOCK_LIST
);
2046 if( xStrm
->GetError() == SVSTREAM_OK
)
2052 if( SVSTREAM_OK
!= rStg
->GetError() )
2054 rStg
->Remove( sStrmName
);
2064 SvxAutocorrWordList
* SvxAutoCorrectLanguageLists::LoadAutocorrWordList()
2066 if( pAutocorr_List
)
2067 pAutocorr_List
->DeleteAndDestroyAll();
2069 pAutocorr_List
= new SvxAutocorrWordList();
2073 uno::Reference
< embed::XStorage
> xStg
= comphelper::OStorageHelper::GetStorageFromURL( sShareAutoCorrFile
, embed::ElementModes::READ
);
2074 String
aXMLWordListName( pXMLImplAutocorr_ListStr
, RTL_TEXTENCODING_MS_1252
);
2075 uno::Reference
< io::XStream
> xStrm
= xStg
->openStreamElement( aXMLWordListName
, embed::ElementModes::READ
);
2076 uno::Reference
< uno::XComponentContext
> xContext
= comphelper::getProcessComponentContext();
2078 xml::sax::InputSource aParserInput
;
2079 aParserInput
.sSystemId
= aXMLWordListName
;
2080 aParserInput
.aInputStream
= xStrm
->getInputStream();
2083 uno::Reference
< xml::sax::XParser
> xParser
= xml::sax::Parser::create(xContext
);
2084 RTL_LOGFILE_PRODUCT_CONTEXT( aLog
, "AutoCorrect Import" );
2085 uno::Reference
< xml::sax::XDocumentHandler
> xFilter
= new SvXMLAutoCorrectImport( xContext
, pAutocorr_List
, rAutoCorrect
, xStg
);
2087 // connect parser and filter
2088 xParser
->setDocumentHandler( xFilter
);
2091 xParser
->parseStream( aParserInput
);
2093 catch ( const uno::Exception
& )
2098 FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile
,
2099 &aModifiedDate
, &aModifiedTime
);
2100 aLastCheckTime
= Time( Time::SYSTEM
);
2102 return pAutocorr_List
;
2105 void SvxAutoCorrectLanguageLists::SetAutocorrWordList( SvxAutocorrWordList
* pList
)
2107 if( pAutocorr_List
&& pList
!= pAutocorr_List
)
2108 delete pAutocorr_List
;
2109 pAutocorr_List
= pList
;
2110 if( !pAutocorr_List
)
2112 OSL_ENSURE( !this, "No valid list" );
2113 pAutocorr_List
= new SvxAutocorrWordList();
2115 nFlags
|= ChgWordLstLoad
;
2118 const SvxAutocorrWordList
* SvxAutoCorrectLanguageLists::GetAutocorrWordList()
2120 if( !( ChgWordLstLoad
& nFlags
) || IsFileChanged_Imp() )
2121 SetAutocorrWordList( LoadAutocorrWordList() );
2122 return pAutocorr_List
;
2125 SvStringsISortDtor
* SvxAutoCorrectLanguageLists::GetCplSttExceptList()
2127 if( !( CplSttLstLoad
& nFlags
) || IsFileChanged_Imp() )
2128 SetCplSttExceptList( LoadCplSttExceptList() );
2129 return pCplStt_ExcptLst
;
2132 sal_Bool
SvxAutoCorrectLanguageLists::AddToCplSttExceptList(const String
& rNew
)
2134 String
* pNew
= new String( rNew
);
2135 if( rNew
.Len() && GetCplSttExceptList()->insert( pNew
).second
)
2137 MakeUserStorage_Impl();
2138 SotStorageRef xStg
= new SotStorage( sUserAutoCorrFile
, STREAM_READWRITE
, sal_True
);
2140 SaveExceptList_Imp( *pCplStt_ExcptLst
, pXMLImplCplStt_ExcptLstStr
, xStg
);
2144 FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile
,
2145 &aModifiedDate
, &aModifiedTime
);
2146 aLastCheckTime
= Time( Time::SYSTEM
);
2149 delete pNew
, pNew
= 0;
2153 sal_Bool
SvxAutoCorrectLanguageLists::AddToWrdSttExceptList(const String
& rNew
)
2155 String
* pNew
= new String( rNew
);
2156 SvStringsISortDtor
* pExceptList
= LoadWrdSttExceptList();
2157 if( rNew
.Len() && pExceptList
&& pExceptList
->insert( pNew
).second
)
2159 MakeUserStorage_Impl();
2160 SotStorageRef xStg
= new SotStorage( sUserAutoCorrFile
, STREAM_READWRITE
, sal_True
);
2162 SaveExceptList_Imp( *pWrdStt_ExcptLst
, pXMLImplWrdStt_ExcptLstStr
, xStg
);
2166 FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile
,
2167 &aModifiedDate
, &aModifiedTime
);
2168 aLastCheckTime
= Time( Time::SYSTEM
);
2171 delete pNew
, pNew
= 0;
2175 SvStringsISortDtor
* SvxAutoCorrectLanguageLists::LoadCplSttExceptList()
2177 SotStorageRef xStg
= new SotStorage( sShareAutoCorrFile
, STREAM_READ
| STREAM_SHARE_DENYNONE
, sal_True
);
2178 String
sTemp ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplCplStt_ExcptLstStr
) );
2179 if( xStg
.Is() && xStg
->IsContained( sTemp
) )
2180 LoadXMLExceptList_Imp( pCplStt_ExcptLst
, pXMLImplCplStt_ExcptLstStr
, xStg
);
2182 return pCplStt_ExcptLst
;
2185 void SvxAutoCorrectLanguageLists::SaveCplSttExceptList()
2187 MakeUserStorage_Impl();
2188 SotStorageRef xStg
= new SotStorage( sUserAutoCorrFile
, STREAM_READWRITE
, sal_True
);
2190 SaveExceptList_Imp( *pCplStt_ExcptLst
, pXMLImplCplStt_ExcptLstStr
, xStg
);
2195 FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile
,
2196 &aModifiedDate
, &aModifiedTime
);
2197 aLastCheckTime
= Time( Time::SYSTEM
);
2200 void SvxAutoCorrectLanguageLists::SetCplSttExceptList( SvStringsISortDtor
* pList
)
2202 if( pCplStt_ExcptLst
&& pList
!= pCplStt_ExcptLst
)
2203 delete pCplStt_ExcptLst
;
2205 pCplStt_ExcptLst
= pList
;
2206 if( !pCplStt_ExcptLst
)
2208 OSL_ENSURE( !this, "No valid list" );
2209 pCplStt_ExcptLst
= new SvStringsISortDtor
;
2211 nFlags
|= CplSttLstLoad
;
2214 SvStringsISortDtor
* SvxAutoCorrectLanguageLists::LoadWrdSttExceptList()
2216 SotStorageRef xStg
= new SotStorage( sShareAutoCorrFile
, STREAM_READ
| STREAM_SHARE_DENYNONE
, sal_True
);
2217 String
sTemp ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplWrdStt_ExcptLstStr
) );
2218 if( xStg
.Is() && xStg
->IsContained( sTemp
) )
2219 LoadXMLExceptList_Imp( pWrdStt_ExcptLst
, pXMLImplWrdStt_ExcptLstStr
, xStg
);
2220 return pWrdStt_ExcptLst
;
2223 void SvxAutoCorrectLanguageLists::SaveWrdSttExceptList()
2225 MakeUserStorage_Impl();
2226 SotStorageRef xStg
= new SotStorage( sUserAutoCorrFile
, STREAM_READWRITE
, sal_True
);
2228 SaveExceptList_Imp( *pWrdStt_ExcptLst
, pXMLImplWrdStt_ExcptLstStr
, xStg
);
2232 FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile
,
2233 &aModifiedDate
, &aModifiedTime
);
2234 aLastCheckTime
= Time( Time::SYSTEM
);
2237 void SvxAutoCorrectLanguageLists::SetWrdSttExceptList( SvStringsISortDtor
* pList
)
2239 if( pWrdStt_ExcptLst
&& pList
!= pWrdStt_ExcptLst
)
2240 delete pWrdStt_ExcptLst
;
2241 pWrdStt_ExcptLst
= pList
;
2242 if( !pWrdStt_ExcptLst
)
2244 OSL_ENSURE( !this, "No valid list" );
2245 pWrdStt_ExcptLst
= new SvStringsISortDtor
;
2247 nFlags
|= WrdSttLstLoad
;
2250 SvStringsISortDtor
* SvxAutoCorrectLanguageLists::GetWrdSttExceptList()
2252 if( !( WrdSttLstLoad
& nFlags
) || IsFileChanged_Imp() )
2253 SetWrdSttExceptList( LoadWrdSttExceptList() );
2254 return pWrdStt_ExcptLst
;
2257 void SvxAutoCorrectLanguageLists::RemoveStream_Imp( const String
& rName
)
2259 if( sShareAutoCorrFile
!= sUserAutoCorrFile
)
2261 SotStorageRef xStg
= new SotStorage( sUserAutoCorrFile
, STREAM_READWRITE
, sal_True
);
2262 if( xStg
.Is() && SVSTREAM_OK
== xStg
->GetError() &&
2263 xStg
->IsStream( rName
) )
2265 xStg
->Remove( rName
);
2273 void SvxAutoCorrectLanguageLists::MakeUserStorage_Impl()
2275 // The conversion needs to happen if the file is already in the user
2276 // directory and is in the old format. Additionally it needs to
2277 // happen when the file is being copied from share to user.
2279 sal_Bool bError
= sal_False
, bConvert
= sal_False
, bCopy
= sal_False
;
2280 INetURLObject aDest
;
2281 INetURLObject aSource
;
2283 if (sUserAutoCorrFile
!= sShareAutoCorrFile
)
2285 aSource
= INetURLObject ( sShareAutoCorrFile
);
2286 aDest
= INetURLObject ( sUserAutoCorrFile
);
2287 if ( SotStorage::IsOLEStorage ( sShareAutoCorrFile
) )
2289 aDest
.SetExtension ( OUString("bak") );
2290 bConvert
= sal_True
;
2294 else if ( SotStorage::IsOLEStorage ( sUserAutoCorrFile
) )
2296 aSource
= INetURLObject ( sUserAutoCorrFile
);
2297 aDest
= INetURLObject ( sUserAutoCorrFile
);
2298 aDest
.SetExtension ( OUString("bak") );
2299 bCopy
= bConvert
= sal_True
;
2305 String
sMain(aDest
.GetMainURL( INetURLObject::DECODE_TO_IURI
));
2306 sal_Unicode cSlash
= '/';
2307 xub_StrLen nSlashPos
= sMain
.SearchBackward(cSlash
);
2308 sMain
.Erase(nSlashPos
);
2309 ::ucbhelper::Content
aNewContent( sMain
, uno::Reference
< XCommandEnvironment
>(), comphelper::getProcessComponentContext() );
2312 aInfo
.NameClash
= NameClash::OVERWRITE
;
2313 aInfo
.NewTitle
= aDest
.GetName();
2314 aInfo
.SourceURL
= aSource
.GetMainURL( INetURLObject::DECODE_TO_IURI
);
2315 aInfo
.MoveData
= sal_False
;
2317 aNewContent
.executeCommand( OUString ( "transfer" ), aAny
);
2324 if (bConvert
&& !bError
)
2326 SotStorageRef xSrcStg
= new SotStorage( aDest
.GetMainURL( INetURLObject::DECODE_TO_IURI
), STREAM_READ
, sal_True
);
2327 SotStorageRef xDstStg
= new SotStorage( sUserAutoCorrFile
, STREAM_WRITE
, sal_True
);
2329 if( xSrcStg
.Is() && xDstStg
.Is() )
2331 String
sXMLWord ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplWrdStt_ExcptLstStr
) );
2332 String
sXMLSentence ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplCplStt_ExcptLstStr
) );
2333 SvStringsISortDtor
*pTmpWordList
= NULL
;
2335 if (xSrcStg
->IsContained( sXMLWord
) )
2336 LoadXMLExceptList_Imp( pTmpWordList
, pXMLImplWrdStt_ExcptLstStr
, xSrcStg
);
2340 SaveExceptList_Imp( *pTmpWordList
, pXMLImplWrdStt_ExcptLstStr
, xDstStg
, sal_True
);
2341 pTmpWordList
->DeleteAndDestroyAll();
2342 pTmpWordList
= NULL
;
2346 if (xSrcStg
->IsContained( sXMLSentence
) )
2347 LoadXMLExceptList_Imp( pTmpWordList
, pXMLImplCplStt_ExcptLstStr
, xSrcStg
);
2351 SaveExceptList_Imp( *pTmpWordList
, pXMLImplCplStt_ExcptLstStr
, xDstStg
, sal_True
);
2352 pTmpWordList
->DeleteAndDestroyAll();
2355 GetAutocorrWordList();
2356 MakeBlocklist_Imp( *xDstStg
);
2357 sShareAutoCorrFile
= sUserAutoCorrFile
;
2361 ::ucbhelper::Content
aContent ( aDest
.GetMainURL( INetURLObject::DECODE_TO_IURI
), uno::Reference
< XCommandEnvironment
>(), comphelper::getProcessComponentContext() );
2362 aContent
.executeCommand ( OUString( "delete" ), makeAny ( sal_Bool (sal_True
) ) );
2369 else if( bCopy
&& !bError
)
2370 sShareAutoCorrFile
= sUserAutoCorrFile
;
2373 sal_Bool
SvxAutoCorrectLanguageLists::MakeBlocklist_Imp( SvStorage
& rStg
)
2375 String
sStrmName( pXMLImplAutocorr_ListStr
, RTL_TEXTENCODING_MS_1252
);
2376 sal_Bool bRet
= sal_True
, bRemove
= !pAutocorr_List
|| pAutocorr_List
->empty();
2379 SvStorageStreamRef refList
= rStg
.OpenSotStream( sStrmName
,
2380 ( STREAM_READ
| STREAM_WRITE
| STREAM_SHARE_DENYWRITE
) );
2383 refList
->SetSize( 0 );
2384 refList
->SetBufferSize( 8192 );
2385 String
aPropName( OUString( "MediaType" ) );
2386 OUString
aMime( "text/xml" );
2389 refList
->SetProperty( aPropName
, aAny
);
2391 uno::Reference
< uno::XComponentContext
> xContext
=
2392 comphelper::getProcessComponentContext();
2394 uno::Reference
< xml::sax::XWriter
> xWriter
= xml::sax::Writer::create(xContext
);
2395 uno::Reference
< io::XOutputStream
> xOut
= new utl::OOutputStreamWrapper( *refList
);
2396 xWriter
->setOutputStream(xOut
);
2398 uno::Reference
<xml::sax::XDocumentHandler
> xHandler(xWriter
, uno::UNO_QUERY
);
2399 SvXMLAutoCorrectExport
aExp( xContext
, pAutocorr_List
, sStrmName
, xHandler
);
2401 aExp
.exportDoc( XML_BLOCK_LIST
);
2404 bRet
= SVSTREAM_OK
== refList
->GetError();
2409 if( SVSTREAM_OK
!= rStg
.GetError() )
2422 rStg
.Remove( sStrmName
);
2429 sal_Bool
SvxAutoCorrectLanguageLists::MakeCombinedChanges( std::vector
<SvxAutocorrWord
>& aNewEntries
, std::vector
<SvxAutocorrWord
>& aDeleteEntries
)
2431 // First get the current list!
2432 GetAutocorrWordList();
2434 MakeUserStorage_Impl();
2435 SotStorageRef xStorage
= new SotStorage( sUserAutoCorrFile
, STREAM_READWRITE
, sal_True
);
2437 sal_Bool bRet
= xStorage
.Is() && SVSTREAM_OK
== xStorage
->GetError();
2441 for ( sal_uInt32 i
=0; i
< aDeleteEntries
.size(); i
++ )
2443 SvxAutocorrWord aWordToDelete
= aDeleteEntries
[i
];
2444 SvxAutocorrWord
*pFoundEntry
= pAutocorr_List
->FindAndRemove( &aWordToDelete
);
2447 if( !pFoundEntry
->IsTextOnly() )
2449 String
aName( aWordToDelete
.GetShort() );
2450 if (xStorage
->IsOLEStorage())
2451 EncryptBlockName_Imp( aName
);
2453 GeneratePackageName ( aWordToDelete
.GetShort(), aName
);
2455 if( xStorage
->IsContained( aName
) )
2457 xStorage
->Remove( aName
);
2458 bRet
= xStorage
->Commit();
2465 for ( sal_uInt32 i
=0; i
< aNewEntries
.size(); i
++ )
2467 SvxAutocorrWord
*pWordToAdd
= new SvxAutocorrWord( aNewEntries
[i
].GetShort(), aNewEntries
[i
].GetLong(), sal_True
);
2468 SvxAutocorrWord
*pRemoved
= pAutocorr_List
->FindAndRemove( pWordToAdd
);
2471 if( !pRemoved
->IsTextOnly() )
2473 // Still have to remove the Storage
2474 String
sStorageName( pWordToAdd
->GetShort() );
2475 if (xStorage
->IsOLEStorage())
2476 EncryptBlockName_Imp( sStorageName
);
2478 GeneratePackageName ( pWordToAdd
->GetShort(), sStorageName
);
2480 if( xStorage
->IsContained( sStorageName
) )
2481 xStorage
->Remove( sStorageName
);
2485 bRet
= pAutocorr_List
->Insert( pWordToAdd
);
2496 bRet
= MakeBlocklist_Imp( *xStorage
);
2502 sal_Bool
SvxAutoCorrectLanguageLists::PutText( const String
& rShort
, const String
& rLong
)
2504 // First get the current list!
2505 GetAutocorrWordList();
2507 MakeUserStorage_Impl();
2508 SotStorageRef xStg
= new SotStorage( sUserAutoCorrFile
, STREAM_READWRITE
, sal_True
);
2510 sal_Bool bRet
= xStg
.Is() && SVSTREAM_OK
== xStg
->GetError();
2512 // Update the word list
2515 SvxAutocorrWord
* pNew
= new SvxAutocorrWord( rShort
, rLong
, sal_True
);
2516 SvxAutocorrWord
*pRemove
= pAutocorr_List
->FindAndRemove( pNew
);
2519 if( !pRemove
->IsTextOnly() )
2521 // Still have to remove the Storage
2522 String
sStgNm( rShort
);
2523 if (xStg
->IsOLEStorage())
2524 EncryptBlockName_Imp( sStgNm
);
2526 GeneratePackageName ( rShort
, sStgNm
);
2528 if( xStg
->IsContained( sStgNm
) )
2529 xStg
->Remove( sStgNm
);
2534 if( pAutocorr_List
->Insert( pNew
) )
2536 bRet
= MakeBlocklist_Imp( *xStg
);
2548 sal_Bool
SvxAutoCorrectLanguageLists::PutText( const String
& rShort
,
2549 SfxObjectShell
& rShell
)
2551 // First get the current list!
2552 GetAutocorrWordList();
2554 MakeUserStorage_Impl();
2556 sal_Bool bRet
= sal_False
;
2560 uno::Reference
< embed::XStorage
> xStg
= comphelper::OStorageHelper::GetStorageFromURL( sUserAutoCorrFile
, embed::ElementModes::READWRITE
);
2561 bRet
= rAutoCorrect
.PutText( xStg
, sUserAutoCorrFile
, rShort
, rShell
, sLong
);
2564 // Update the word list
2567 SvxAutocorrWord
* pNew
= new SvxAutocorrWord( rShort
, sLong
, sal_False
);
2568 if( pAutocorr_List
->Insert( pNew
) )
2570 SotStorageRef xStor
= new SotStorage( sUserAutoCorrFile
, STREAM_READWRITE
, sal_True
);
2571 MakeBlocklist_Imp( *xStor
);
2577 catch ( const uno::Exception
& )
2585 sal_Bool
SvxAutoCorrectLanguageLists::DeleteText( const String
& rShort
)
2587 // First get the current list!
2588 GetAutocorrWordList();
2590 MakeUserStorage_Impl();
2592 SotStorageRef xStg
= new SotStorage( sUserAutoCorrFile
, STREAM_READWRITE
, sal_True
);
2593 sal_Bool bRet
= xStg
.Is() && SVSTREAM_OK
== xStg
->GetError();
2596 SvxAutocorrWord
aTmp( rShort
, rShort
);
2597 SvxAutocorrWord
*pFnd
= pAutocorr_List
->FindAndRemove( &aTmp
);
2600 if( !pFnd
->IsTextOnly() )
2602 String
aName( rShort
);
2603 if (xStg
->IsOLEStorage())
2604 EncryptBlockName_Imp( aName
);
2606 GeneratePackageName ( rShort
, aName
);
2607 if( xStg
->IsContained( aName
) )
2609 xStg
->Remove( aName
);
2610 bRet
= xStg
->Commit();
2615 MakeBlocklist_Imp( *xStg
);
2624 // Keep the list sorted ...
2625 bool CompareSvxAutocorrWordList::operator()( SvxAutocorrWord
* const& lhs
, SvxAutocorrWord
* const& rhs
) const
2627 CollatorWrapper
& rCmp
= ::GetCollatorWrapper();
2628 return rCmp
.compareString( lhs
->GetShort(), rhs
->GetShort() ) < 0;
2631 SvxAutocorrWordList::~SvxAutocorrWordList()
2633 DeleteAndDestroyAll();
2636 void SvxAutocorrWordList::DeleteAndDestroyAll()
2638 for( SvxAutocorrWordList_Hash::const_iterator it
= maHash
.begin(); it
!= maHash
.end(); ++it
)
2642 for( SvxAutocorrWordList_Set::const_iterator it2
= maSet
.begin(); it2
!= maSet
.end(); ++it2
)
2647 // returns true if inserted
2648 bool SvxAutocorrWordList::Insert(SvxAutocorrWord
*pWord
)
2650 if ( maSet
.empty() ) // use the hash
2652 OUString
aShort( pWord
->GetShort() );
2653 return maHash
.insert( std::pair
<OUString
, SvxAutocorrWord
*>( aShort
, pWord
) ).second
;
2656 return maSet
.insert( pWord
).second
;
2659 void SvxAutocorrWordList::LoadEntry(String sWrong
, String sRight
, sal_Bool bOnlyTxt
)
2661 SvxAutocorrWord
* pNew
= new SvxAutocorrWord( sWrong
, sRight
, bOnlyTxt
);
2662 if( !Insert( pNew
) )
2666 bool SvxAutocorrWordList::empty() const
2668 return maHash
.empty() && maSet
.empty();
2671 SvxAutocorrWord
*SvxAutocorrWordList::FindAndRemove(SvxAutocorrWord
*pWord
)
2673 SvxAutocorrWord
*pMatch
= NULL
;
2675 if ( maSet
.empty() ) // use the hash
2677 SvxAutocorrWordList_Hash::iterator it
= maHash
.find( pWord
->GetShort() );
2678 if( it
!= maHash
.end() )
2680 pMatch
= it
->second
;
2686 SvxAutocorrWordList_Set::iterator it
= maSet
.find( pWord
);
2687 if( it
!= maSet
.end() )
2696 // return the sorted contents - defer sorting until we have to.
2697 SvxAutocorrWordList::Content
SvxAutocorrWordList::getSortedContent() const
2701 // convert from hash to set permanantly
2702 if ( maSet
.empty() )
2704 // This beasty has some O(N log(N)) in a terribly slow ICU collate fn.
2705 for( SvxAutocorrWordList_Hash::const_iterator it
= maHash
.begin(); it
!= maHash
.end(); ++it
)
2706 maSet
.insert( it
->second
);
2709 for( SvxAutocorrWordList_Set::const_iterator it
= maSet
.begin(); it
!= maSet
.end(); ++it
)
2710 aContent
.push_back( *it
);
2715 bool SvxAutocorrWordList::WordMatches(const SvxAutocorrWord
*pFnd
,
2718 xub_StrLen nEndPos
) const
2720 const String
& rChk
= pFnd
->GetShort();
2721 if( nEndPos
>= rChk
.Len() )
2723 xub_StrLen nCalcStt
= nEndPos
- rChk
.Len();
2724 if( ( !nCalcStt
|| nCalcStt
== rStt
||
2725 ( nCalcStt
< rStt
&&
2726 IsWordDelim( rTxt
.GetChar( nCalcStt
- 1 ) ))) )
2728 TransliterationWrapper
& rCmp
= GetIgnoreTranslWrapper();
2730 OUString
sWord(rTxt
.GetBuffer() + nCalcStt
, rChk
.Len());
2731 if( rCmp
.isEqual( rChk
, sWord
))
2741 const SvxAutocorrWord
* SvxAutocorrWordList::SearchWordsInList(const String
& rTxt
, xub_StrLen
& rStt
,
2742 xub_StrLen nEndPos
) const
2744 for( SvxAutocorrWordList_Hash::const_iterator it
= maHash
.begin(); it
!= maHash
.end(); ++it
)
2746 if( WordMatches( it
->second
, rTxt
, rStt
, nEndPos
) )
2750 for( SvxAutocorrWordList_Set::const_iterator it2
= maSet
.begin(); it2
!= maSet
.end(); ++it2
)
2752 if( WordMatches( *it2
, rTxt
, rStt
, nEndPos
) )
2758 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */