merge the formfield patch from ooo-build
[ooovba.git] / svx / source / editeng / svxacorr.cxx
blobfd7b0936af7550a982db73e62b480f1188023a04
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: svxacorr.cxx,v $
10 * $Revision: 1.62 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
35 #include <com/sun/star/io/XStream.hpp>
36 #include <com/sun/star/lang/Locale.hpp>
37 #include <tools/urlobj.hxx>
38 #include <tools/table.hxx>
39 #include <i18npool/mslangid.hxx>
40 #ifndef _APP_HXX //autogen
41 #include <vcl/svapp.hxx>
42 #endif
43 #ifndef _STORINFO_HXX //autogen
44 #include <sot/storinfo.hxx>
45 #endif
46 #ifndef _SFX_DOCFILE_HXX
47 #include <sfx2/docfile.hxx>
48 #endif
49 #include <sfx2/sfxhelp.hxx>
50 #include <sfx2/viewfrm.hxx>
51 // fuer die Sort-String-Arrays aus dem SVMEM.HXX
52 #define _SVSTDARR_STRINGSISORTDTOR
53 #define _SVSTDARR_STRINGSDTOR
54 #include <svtools/svstdarr.hxx>
56 #ifndef SVTOOLS_FSTATHELPER_HXX
57 #include <svtools/fstathelper.hxx>
58 #endif
59 #include <svtools/helpopt.hxx>
60 #include <svtools/urihelper.hxx>
61 #include <unotools/charclass.hxx>
62 #ifndef _COM_SUN_STAR_I18N_UNICODETYPE_HDL_
63 #include <com/sun/star/i18n/UnicodeType.hdl>
64 #endif
65 #include <unotools/collatorwrapper.hxx>
66 #include <com/sun/star/i18n/CollatorOptions.hpp>
67 #include <unotools/localedatawrapper.hxx>
68 #include <unotools/transliterationwrapper.hxx>
69 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
70 #include <comphelper/processfactory.hxx>
71 #include <com/sun/star/io/XActiveDataSource.hpp>
73 #ifndef _SVX_SVXIDS_HRC
74 #include <svx/svxids.hrc>
75 #endif
77 #include <sot/storage.hxx>
78 #include <comphelper/storagehelper.hxx>
80 #include <svx/udlnitem.hxx>
81 #include <svx/wghtitem.hxx>
82 #include <svx/escpitem.hxx>
83 #include <svx/svxacorr.hxx>
84 #include "unolingu.hxx"
85 #include "vcl/window.hxx"
87 #ifndef _SVX_HELPID_HRC
88 #include <helpid.hrc>
89 #endif
90 #include <comphelper/processfactory.hxx>
91 #include <com/sun/star/xml/sax/InputSource.hpp>
92 #include <com/sun/star/xml/sax/XParser.hpp>
93 #include <unotools/streamwrap.hxx>
94 #include <SvXMLAutoCorrectImport.hxx>
95 #include <SvXMLAutoCorrectExport.hxx>
96 #include <ucbhelper/content.hxx>
97 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
98 #include <com/sun/star/ucb/TransferInfo.hpp>
99 #include <com/sun/star/ucb/NameClash.hpp>
100 #include <xmloff/xmltoken.hxx>
102 #define CHAR_HARDBLANK ((sal_Unicode)0x00A0)
104 using namespace ::com::sun::star::ucb;
105 using namespace ::com::sun::star::uno;
106 using namespace ::com::sun::star;
107 using namespace ::xmloff::token;
108 using namespace ::rtl;
109 using namespace ::utl;
111 const int C_NONE = 0x00;
112 const int C_FULL_STOP = 0x01;
113 const int C_EXCLAMATION_MARK = 0x02;
114 const int C_QUESTION_MARK = 0x04;
116 static const sal_Char pImplWrdStt_ExcptLstStr[] = "WordExceptList";
117 static const sal_Char pImplCplStt_ExcptLstStr[] = "SentenceExceptList";
118 static const sal_Char pImplAutocorr_ListStr[] = "DocumentList";
119 static const sal_Char pXMLImplWrdStt_ExcptLstStr[] = "WordExceptList.xml";
120 static const sal_Char pXMLImplCplStt_ExcptLstStr[] = "SentenceExceptList.xml";
121 static const sal_Char pXMLImplAutocorr_ListStr[] = "DocumentList.xml";
123 static const sal_Char
124 /* auch bei diesen Anfaengen - Klammern auf und alle Arten von Anf.Zei. */
125 sImplSttSkipChars[] = "\"\'([{\x83\x84\x89\x91\x92\x93\x94",
126 /* auch bei diesen Ende - Klammern auf und alle Arten von Anf.Zei. */
127 sImplEndSkipChars[] = "\"\')]}\x83\x84\x89\x91\x92\x93\x94";
129 // diese Zeichen sind in Worten erlaubt: (fuer FnCptlSttSntnc)
130 static const sal_Char sImplWordChars[] = "-'";
132 void EncryptBlockName_Imp( String& rName );
133 void DecryptBlockName_Imp( String& rName );
136 // FileVersions Nummern fuer die Ersetzungs-/Ausnahmelisten getrennt
137 #define WORDLIST_VERSION_358 1
138 #define EXEPTLIST_VERSION_358 0
141 _SV_IMPL_SORTAR_ALG( SvxAutocorrWordList, SvxAutocorrWordPtr )
142 TYPEINIT0(SvxAutoCorrect)
144 typedef SvxAutoCorrectLanguageLists* SvxAutoCorrectLanguageListsPtr;
145 DECLARE_TABLE( SvxAutoCorrLanguageTable_Impl, SvxAutoCorrectLanguageListsPtr)
147 DECLARE_TABLE( SvxAutoCorrLastFileAskTable_Impl, long )
150 inline int IsWordDelim( const sal_Unicode c )
152 return ' ' == c || '\t' == c || 0x0a == c ||
153 0xA0 == c || 0x2011 == c || 0x1 == c;
156 inline int IsLowerLetter( sal_Int32 nCharType )
158 return CharClass::isLetterType( nCharType ) &&
159 0 == ( ::com::sun::star::i18n::KCharacterType::UPPER & nCharType);
161 inline int IsUpperLetter( sal_Int32 nCharType )
163 return CharClass::isLetterType( nCharType ) &&
164 0 == ( ::com::sun::star::i18n::KCharacterType::LOWER & nCharType);
167 BOOL lcl_IsSymbolChar( CharClass& rCC, const String& rTxt,
168 xub_StrLen nStt, xub_StrLen nEnd )
170 for( ; nStt < nEnd; ++nStt )
172 #if OSL_DEBUG_LEVEL > 1
173 sal_Int32 nCharType;
174 sal_Int32 nChType;
175 nCharType = rCC.getCharacterType( rTxt, nStt );
176 nChType = rCC.getType( rTxt, nStt );
177 #endif
178 if( ::com::sun::star::i18n::UnicodeType::PRIVATE_USE ==
179 rCC.getType( rTxt, nStt ))
180 return TRUE;
182 return FALSE;
186 static BOOL lcl_IsInAsciiArr( const sal_Char* pArr, const sal_Unicode c )
188 BOOL bRet = FALSE;
189 for( ; *pArr; ++pArr )
190 if( *pArr == c )
192 bRet = TRUE;
193 break;
195 return bRet;
198 SvxAutoCorrDoc::~SvxAutoCorrDoc()
203 // wird nach dem austauschen der Zeichen von den Funktionen
204 // - FnCptlSttWrd
205 // - FnCptlSttSntnc
206 // gerufen. Dann koennen die Worte ggfs. in die Ausnahmelisten
207 // aufgenommen werden.
208 void SvxAutoCorrDoc::SaveCpltSttWord( ULONG, xub_StrLen, const String&,
209 sal_Unicode )
213 LanguageType SvxAutoCorrDoc::GetLanguage( xub_StrLen , BOOL ) const
215 return LANGUAGE_SYSTEM;
218 static ::com::sun::star::uno::Reference<
219 ::com::sun::star::lang::XMultiServiceFactory >& GetProcessFact()
221 static ::com::sun::star::uno::Reference<
222 ::com::sun::star::lang::XMultiServiceFactory > xMSF =
223 ::comphelper::getProcessServiceFactory();
224 return xMSF;
227 static USHORT GetAppLang()
229 return Application::GetSettings().GetLanguage();
231 static LocaleDataWrapper& GetLocaleDataWrapper( USHORT nLang )
233 static LocaleDataWrapper aLclDtWrp( GetProcessFact(),
234 SvxCreateLocale( GetAppLang() ) );
235 ::com::sun::star::lang::Locale aLcl( SvxCreateLocale( nLang ));
236 const ::com::sun::star::lang::Locale& rLcl = aLclDtWrp.getLoadedLocale();
237 if( aLcl.Language != rLcl.Language ||
238 aLcl.Country != rLcl.Country ||
239 aLcl.Variant != rLcl.Variant )
240 aLclDtWrp.setLocale( aLcl );
241 return aLclDtWrp;
243 static TransliterationWrapper& GetIgnoreTranslWrapper()
245 static int bIsInit = 0;
246 static TransliterationWrapper aWrp( GetProcessFact(),
247 ::com::sun::star::i18n::TransliterationModules_IGNORE_CASE |
248 ::com::sun::star::i18n::TransliterationModules_IGNORE_KANA |
249 ::com::sun::star::i18n::TransliterationModules_IGNORE_WIDTH );
250 if( !bIsInit )
252 aWrp.loadModuleIfNeeded( GetAppLang() );
253 bIsInit = 1;
255 return aWrp;
257 static CollatorWrapper& GetCollatorWrapper()
259 static int bIsInit = 0;
260 static CollatorWrapper aCollWrp( GetProcessFact() );
261 if( !bIsInit )
263 aCollWrp.loadDefaultCollator( SvxCreateLocale( GetAppLang() ), 0 );
264 bIsInit = 1;
266 return aCollWrp;
270 void SvxAutocorrWordList::DeleteAndDestroy( USHORT nP, USHORT nL )
272 if( nL )
274 DBG_ASSERT( nP < nA && nP + nL <= nA, "ERR_VAR_DEL" );
275 for( USHORT n=nP; n < nP + nL; n++ )
276 delete *((SvxAutocorrWordPtr*)pData+n);
277 SvPtrarr::Remove( nP, nL );
282 BOOL SvxAutocorrWordList::Seek_Entry( const SvxAutocorrWordPtr aE, USHORT* pP ) const
284 register USHORT nO = SvxAutocorrWordList_SAR::Count(),
286 nU = 0;
287 if( nO > 0 )
289 CollatorWrapper& rCmp = ::GetCollatorWrapper();
290 nO--;
291 while( nU <= nO )
293 nM = nU + ( nO - nU ) / 2;
294 long nCmp = rCmp.compareString( aE->GetShort(),
295 (*((SvxAutocorrWordPtr*)pData + nM))->GetShort() );
296 if( 0 == nCmp )
298 if( pP ) *pP = nM;
299 return TRUE;
301 else if( 0 < nCmp )
302 nU = nM + 1;
303 else if( nM == 0 )
305 if( pP ) *pP = nU;
306 return FALSE;
308 else
309 nO = nM - 1;
312 if( pP ) *pP = nU;
313 return FALSE;
316 /* -----------------18.11.98 15:28-------------------
318 * --------------------------------------------------*/
319 void lcl_ClearTable(SvxAutoCorrLanguageTable_Impl& rLangTable)
321 SvxAutoCorrectLanguageListsPtr pLists = rLangTable.Last();
322 while(pLists)
324 delete pLists;
325 pLists = rLangTable.Prev();
327 rLangTable.Clear();
330 /* -----------------03.11.06 10:15-------------------
332 * --------------------------------------------------*/
334 sal_Bool SvxAutoCorrect::IsAutoCorrectChar( sal_Unicode cChar )
336 return cChar == '\0' || cChar == '\t' || cChar == 0x0a ||
337 cChar == ' ' || cChar == '\'' || cChar == '\"' ||
338 cChar == '*' || cChar == '_' ||
339 cChar == '.' || cChar == ',' || cChar == ';' ||
340 cChar == ':' || cChar == '?' || cChar == '!';
343 /* -----------------19.11.98 10:15-------------------
345 * --------------------------------------------------*/
346 long SvxAutoCorrect::GetDefaultFlags()
348 long nRet = Autocorrect
349 | CptlSttSntnc
350 | CptlSttWrd
351 | ChgFractionSymbol
352 | ChgOrdinalNumber
353 | ChgToEnEmDash
354 | AddNonBrkSpace
355 | ChgWeightUnderl
356 | SetINetAttr
357 | ChgQuotes
358 | SaveWordCplSttLst
359 | SaveWordWrdSttLst
360 | CorrectCapsLock;
361 LanguageType eLang = GetAppLang();
362 switch( eLang )
364 case LANGUAGE_ENGLISH:
365 case LANGUAGE_ENGLISH_US:
366 case LANGUAGE_ENGLISH_UK:
367 case LANGUAGE_ENGLISH_AUS:
368 case LANGUAGE_ENGLISH_CAN:
369 case LANGUAGE_ENGLISH_NZ:
370 case LANGUAGE_ENGLISH_EIRE:
371 case LANGUAGE_ENGLISH_SAFRICA:
372 case LANGUAGE_ENGLISH_JAMAICA:
373 case LANGUAGE_ENGLISH_CARRIBEAN:
374 nRet &= ~(ChgQuotes|ChgSglQuotes);
375 break;
377 return nRet;
381 SvxAutoCorrect::SvxAutoCorrect( const String& rShareAutocorrFile,
382 const String& rUserAutocorrFile )
383 : sShareAutoCorrFile( rShareAutocorrFile ),
384 sUserAutoCorrFile( rUserAutocorrFile ),
385 pLangTable( new SvxAutoCorrLanguageTable_Impl ),
386 pLastFileTable( new SvxAutoCorrLastFileAskTable_Impl ),
387 pCharClass( 0 ),
388 cStartDQuote( 0 ), cEndDQuote( 0 ), cStartSQuote( 0 ), cEndSQuote( 0 )
390 nFlags = SvxAutoCorrect::GetDefaultFlags();
392 c1Div2 = ByteString::ConvertToUnicode( '\xBD', RTL_TEXTENCODING_MS_1252 );
393 c1Div4 = ByteString::ConvertToUnicode( '\xBC', RTL_TEXTENCODING_MS_1252 );
394 c3Div4 = ByteString::ConvertToUnicode( '\xBE', RTL_TEXTENCODING_MS_1252 );
395 cEmDash = ByteString::ConvertToUnicode( '\x97', RTL_TEXTENCODING_MS_1252 );
396 cEnDash = ByteString::ConvertToUnicode( '\x96', RTL_TEXTENCODING_MS_1252 );
399 SvxAutoCorrect::SvxAutoCorrect( const SvxAutoCorrect& rCpy )
400 : sShareAutoCorrFile( rCpy.sShareAutoCorrFile ),
401 sUserAutoCorrFile( rCpy.sUserAutoCorrFile ),
403 aSwFlags( rCpy.aSwFlags ),
405 pLangTable( new SvxAutoCorrLanguageTable_Impl ),
406 pLastFileTable( new SvxAutoCorrLastFileAskTable_Impl ),
407 pCharClass( 0 ),
409 nFlags( rCpy.nFlags & ~(ChgWordLstLoad|CplSttLstLoad|WrdSttLstLoad)),
410 cStartDQuote( rCpy.cStartDQuote ), cEndDQuote( rCpy.cEndDQuote ),
411 cStartSQuote( rCpy.cStartSQuote ), cEndSQuote( rCpy.cEndSQuote ),
412 c1Div2( rCpy.c1Div2 ), c1Div4( rCpy.c1Div4 ), c3Div4( rCpy.c3Div4 ),
413 cEmDash( rCpy.cEmDash ), cEnDash( rCpy.cEnDash )
418 SvxAutoCorrect::~SvxAutoCorrect()
420 lcl_ClearTable(*pLangTable);
421 delete pLangTable;
422 delete pLastFileTable;
423 delete pCharClass;
426 void SvxAutoCorrect::_GetCharClass( LanguageType eLang )
428 delete pCharClass;
429 pCharClass = new CharClass( SvxCreateLocale( eLang ));
430 eCharClassLang = eLang;
433 void SvxAutoCorrect::SetAutoCorrFlag( long nFlag, BOOL bOn )
435 long nOld = nFlags;
436 nFlags = bOn ? nFlags | nFlag
437 : nFlags & ~nFlag;
439 if( !bOn )
441 if( (nOld & CptlSttSntnc) != (nFlags & CptlSttSntnc) )
442 nFlags &= ~CplSttLstLoad;
443 if( (nOld & CptlSttWrd) != (nFlags & CptlSttWrd) )
444 nFlags &= ~WrdSttLstLoad;
445 if( (nOld & Autocorrect) != (nFlags & Autocorrect) )
446 nFlags &= ~ChgWordLstLoad;
451 // Zwei Grossbuchstaben am Wort-Anfang ??
452 BOOL SvxAutoCorrect::FnCptlSttWrd( SvxAutoCorrDoc& rDoc, const String& rTxt,
453 xub_StrLen nSttPos, xub_StrLen nEndPos,
454 LanguageType eLang )
456 BOOL bRet = FALSE;
457 CharClass& rCC = GetCharClass( eLang );
459 // loesche alle nicht alpanum. Zeichen am Wortanfang/-ende und
460 // teste dann ( erkennt: "(min.", "/min.", usw.)
461 for( ; nSttPos < nEndPos; ++nSttPos )
462 if( rCC.isLetterNumeric( rTxt, nSttPos ))
463 break;
464 for( ; nSttPos < nEndPos; --nEndPos )
465 if( rCC.isLetterNumeric( rTxt, nEndPos - 1 ))
466 break;
468 // Zwei Grossbuchstaben am Wort-Anfang ??
469 if( nSttPos+2 < nEndPos &&
470 IsUpperLetter( rCC.getCharacterType( rTxt, nSttPos )) &&
471 IsUpperLetter( rCC.getCharacterType( rTxt, ++nSttPos )) &&
472 // ist das 3. Zeichen ein klein geschiebenes Alpha-Zeichen
473 IsLowerLetter( rCC.getCharacterType( rTxt, nSttPos +1 )) &&
474 // keine Sonder-Attribute ersetzen
475 0x1 != rTxt.GetChar( nSttPos ) && 0x2 != rTxt.GetChar( nSttPos ))
477 // teste ob das Wort in einer Ausnahmeliste steht
478 String sWord( rTxt.Copy( nSttPos - 1, nEndPos - nSttPos + 1 ));
479 if( !FindInWrdSttExceptList(eLang, sWord) )
481 sal_Unicode cSave = rTxt.GetChar( nSttPos );
482 String sChar( cSave );
483 rCC.toLower( sChar );
484 if( sChar.GetChar(0) != cSave && rDoc.Replace( nSttPos, sChar ))
486 if( SaveWordWrdSttLst & nFlags )
487 rDoc.SaveCpltSttWord( CptlSttWrd, nSttPos, sWord, cSave );
488 bRet = TRUE;
492 return bRet;
496 BOOL SvxAutoCorrect::FnChgFractionSymbol(
497 SvxAutoCorrDoc& rDoc, const String& rTxt,
498 xub_StrLen nSttPos, xub_StrLen nEndPos )
500 sal_Unicode cChar = 0;
502 for( ; nSttPos < nEndPos; ++nSttPos )
503 if( !lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nSttPos ) ))
504 break;
505 for( ; nSttPos < nEndPos; --nEndPos )
506 if( !lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nEndPos - 1 ) ))
507 break;
509 // 1/2, 1/4, ... ersetzen durch das entsprechende Zeichen vom Font
510 if( 3 == nEndPos - nSttPos && '/' == rTxt.GetChar( nSttPos+1 ))
512 switch( ( rTxt.GetChar( nSttPos )) * 256 + rTxt.GetChar( nEndPos-1 ))
514 case '1' * 256 + '2': cChar = c1Div2; break;
515 case '1' * 256 + '4': cChar = c1Div4; break;
516 case '3' * 256 + '4': cChar = c3Div4; break;
519 if( cChar )
521 // also austauschen:
522 rDoc.Delete( nSttPos+1, nEndPos );
523 rDoc.Replace( nSttPos, cChar );
526 return 0 != cChar;
530 BOOL SvxAutoCorrect::FnChgOrdinalNumber(
531 SvxAutoCorrDoc& rDoc, const String& rTxt,
532 xub_StrLen nSttPos, xub_StrLen nEndPos,
533 LanguageType eLang )
535 // 1st, 2nd, 3rd, 4 - 0th
536 // 201th oder 201st
537 // 12th oder 12nd
538 CharClass& rCC = GetCharClass( eLang );
539 BOOL bChg = FALSE;
541 for( ; nSttPos < nEndPos; ++nSttPos )
542 if( !lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nSttPos ) ))
543 break;
544 for( ; nSttPos < nEndPos; --nEndPos )
545 if( !lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nEndPos - 1 ) ))
546 break;
548 if( 2 < nEndPos - nSttPos &&
549 rCC.isDigit( rTxt, nEndPos - 3 ) )
551 static sal_Char __READONLY_DATA
552 sAll[] = "th", /* rest */
553 sFirst[] = "st", /* 1 */
554 sSecond[] = "nd", /* 2 */
555 sThird[] = "rd"; /* 3 */
556 static const sal_Char* __READONLY_DATA aNumberTab[ 4 ] =
558 sAll, sFirst, sSecond, sThird
561 sal_Unicode c = rTxt.GetChar( nEndPos - 3 );
562 if( ( c -= '0' ) > 3 )
563 c = 0;
565 bChg = ( ((sal_Unicode)*((aNumberTab[ c ])+0)) ==
566 rTxt.GetChar( nEndPos - 2 ) &&
567 ((sal_Unicode)*((aNumberTab[ c ])+1)) ==
568 rTxt.GetChar( nEndPos - 1 )) ||
569 ( 3 < nEndPos - nSttPos &&
570 ( ((sal_Unicode)*(sAll+0)) == rTxt.GetChar( nEndPos - 2 ) &&
571 ((sal_Unicode)*(sAll+1)) == rTxt.GetChar( nEndPos - 1 )));
573 if( bChg )
575 // dann pruefe mal, ob alle bis zum Start alle Zahlen sind
576 for( xub_StrLen n = nEndPos - 3; nSttPos < n; )
577 if( !rCC.isDigit( rTxt, --n ) )
579 bChg = !rCC.isLetter( rTxt, n );
580 break;
583 if( bChg ) // dann setze mal das Escapement Attribut
585 SvxEscapementItem aSvxEscapementItem( DFLT_ESC_AUTO_SUPER,
586 DFLT_ESC_PROP, SID_ATTR_CHAR_ESCAPEMENT );
587 rDoc.SetAttr( nEndPos - 2, nEndPos,
588 SID_ATTR_CHAR_ESCAPEMENT,
589 aSvxEscapementItem);
594 return bChg;
598 BOOL SvxAutoCorrect::FnChgToEnEmDash(
599 SvxAutoCorrDoc& rDoc, const String& rTxt,
600 xub_StrLen nSttPos, xub_StrLen nEndPos,
601 LanguageType eLang )
603 BOOL bRet = FALSE;
604 CharClass& rCC = GetCharClass( eLang );
605 if (eLang == LANGUAGE_SYSTEM)
606 eLang = GetAppLang();
607 bool bAlwaysUseEmDash = (cEmDash && (eLang == LANGUAGE_RUSSIAN || eLang == LANGUAGE_UKRAINIAN));
609 // ersetze " - " oder " --" durch "enDash"
610 if( cEnDash && 1 < nSttPos && 1 <= nEndPos - nSttPos )
612 sal_Unicode cCh = rTxt.GetChar( nSttPos );
613 if( '-' == cCh )
615 if( ' ' == rTxt.GetChar( nSttPos-1 ) &&
616 '-' == rTxt.GetChar( nSttPos+1 ))
618 xub_StrLen n;
619 for( n = nSttPos+2; n < nEndPos && lcl_IsInAsciiArr(
620 sImplSttSkipChars,(cCh = rTxt.GetChar( n )));
621 ++n )
624 // found: " --[<AnySttChars>][A-z0-9]
625 if( rCC.isLetterNumeric( cCh ) )
627 for( n = nSttPos-1; n && lcl_IsInAsciiArr(
628 sImplEndSkipChars,(cCh = rTxt.GetChar( --n ))); )
631 // found: "[A-z0-9][<AnyEndChars>] --[<AnySttChars>][A-z0-9]
632 if( rCC.isLetterNumeric( cCh ))
634 rDoc.Delete( nSttPos, nSttPos + 2 );
635 rDoc.Insert( nSttPos, bAlwaysUseEmDash ? cEmDash : cEnDash );
636 bRet = TRUE;
641 else if( 3 < nSttPos &&
642 ' ' == rTxt.GetChar( nSttPos-1 ) &&
643 '-' == rTxt.GetChar( nSttPos-2 ))
645 xub_StrLen n, nLen = 1, nTmpPos = nSttPos - 2;
646 if( '-' == ( cCh = rTxt.GetChar( nTmpPos-1 )) )
648 --nTmpPos;
649 ++nLen;
650 cCh = rTxt.GetChar( nTmpPos-1 );
652 if( ' ' == cCh )
654 for( n = nSttPos; n < nEndPos && lcl_IsInAsciiArr(
655 sImplSttSkipChars,(cCh = rTxt.GetChar( n )));
656 ++n )
659 // found: " - [<AnySttChars>][A-z0-9]
660 if( rCC.isLetterNumeric( cCh ) )
662 cCh = ' ';
663 for( n = nTmpPos-1; n && lcl_IsInAsciiArr(
664 sImplEndSkipChars,(cCh = rTxt.GetChar( --n ))); )
666 // found: "[A-z0-9][<AnyEndChars>] - [<AnySttChars>][A-z0-9]
667 if( rCC.isLetterNumeric( cCh ))
669 rDoc.Delete( nTmpPos, nTmpPos + nLen );
670 rDoc.Insert( nTmpPos, bAlwaysUseEmDash ? cEmDash : cEnDash );
671 bRet = TRUE;
678 // Replace [A-z0-9]--[A-z0-9] double dash with "emDash" or "enDash".
679 // Finnish and Hungarian use enDash instead of emDash.
680 bool bEnDash = (eLang == LANGUAGE_HUNGARIAN || eLang == LANGUAGE_FINNISH);
681 if( ((cEmDash && !bEnDash) || (cEnDash && bEnDash)) && 4 <= nEndPos - nSttPos )
683 String sTmp( rTxt.Copy( nSttPos, nEndPos - nSttPos ) );
684 xub_StrLen nFndPos = sTmp.SearchAscii( "--" );
685 if( STRING_NOTFOUND != nFndPos && nFndPos &&
686 nFndPos + 2 < sTmp.Len() &&
687 ( rCC.isLetterNumeric( sTmp, nFndPos - 1 ) ||
688 lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nFndPos - 1 ) )) &&
689 ( rCC.isLetterNumeric( sTmp, nFndPos + 2 ) ||
690 lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nFndPos + 2 ) )))
692 nSttPos = nSttPos + nFndPos;
693 rDoc.Delete( nSttPos, nSttPos + 2 );
694 rDoc.Insert( nSttPos, (bEnDash ? cEnDash : cEmDash) );
695 bRet = TRUE;
698 return bRet;
701 BOOL SvxAutoCorrect::FnAddNonBrkSpace(
702 SvxAutoCorrDoc& rDoc, const String& rTxt,
703 xub_StrLen , xub_StrLen nEndPos,
704 LanguageType eLang )
706 bool bRet = false;
708 CharClass& rCC = GetCharClass( eLang );
709 const lang::Locale rLocale = rCC.getLocale( );
711 if ( rLocale.Language == OUString::createFromAscii( "fr" ) )
713 sal_Unicode cChar = rTxt.GetChar( nEndPos );
714 if ( cChar == ':' || cChar == ';' || cChar == '!' || cChar == '?' )
716 // Check the previous char
717 sal_Unicode cPrevChar = rTxt.GetChar( nEndPos - 1 );
718 if ( cPrevChar != ':' && cPrevChar != ';' && cPrevChar != '!' && cPrevChar != '?' )
720 // Remove any previous normal space
721 xub_StrLen nPos = nEndPos - 1;
722 while ( cPrevChar == ' ' || cPrevChar == CHAR_HARDBLANK )
724 if ( nPos == 0 ) break;
725 nPos--;
726 cPrevChar = rTxt.GetChar( nPos );
729 if ( nPos != 0 )
731 nPos++;
732 if ( nEndPos - nPos > 0 )
733 rDoc.Delete( nPos, nEndPos );
735 // Add the non-breaking space at the end pos
736 rDoc.Insert( nPos, CHAR_HARDBLANK );
737 bRet = true;
743 return bRet;
746 BOOL SvxAutoCorrect::FnSetINetAttr( SvxAutoCorrDoc& rDoc, const String& rTxt,
747 xub_StrLen nSttPos, xub_StrLen nEndPos,
748 LanguageType eLang )
750 String sURL( URIHelper::FindFirstURLInText( rTxt, nSttPos, nEndPos,
751 GetCharClass( eLang ) ));
752 BOOL bRet = 0 != sURL.Len();
753 if( bRet ) // also Attribut setzen:
754 rDoc.SetINetAttr( nSttPos, nEndPos, sURL );
755 return bRet;
759 BOOL SvxAutoCorrect::FnChgWeightUnderl( SvxAutoCorrDoc& rDoc, const String& rTxt,
760 xub_StrLen, xub_StrLen nEndPos,
761 LanguageType eLang )
763 // Bedingung:
764 // Am Anfang: _ oder * hinter Space mit nachfolgenden !Space
765 // Am Ende: _ oder * vor Space (Worttrenner?)
767 sal_Unicode c, cInsChar = rTxt.GetChar( nEndPos ); // unterstreichen oder fett
768 if( ++nEndPos != rTxt.Len() &&
769 !IsWordDelim( rTxt.GetChar( nEndPos ) ) )
770 return FALSE;
772 --nEndPos;
774 BOOL bAlphaNum = FALSE;
775 xub_StrLen nPos = nEndPos, nFndPos = STRING_NOTFOUND;
776 CharClass& rCC = GetCharClass( eLang );
778 while( nPos )
780 switch( c = rTxt.GetChar( --nPos ) )
782 case '_':
783 case '*':
784 if( c == cInsChar )
786 if( bAlphaNum && nPos+1 < nEndPos && ( !nPos ||
787 IsWordDelim( rTxt.GetChar( nPos-1 ))) &&
788 !IsWordDelim( rTxt.GetChar( nPos+1 )))
789 nFndPos = nPos;
790 else
791 // Bedingung ist nicht erfuellt, also abbrechen
792 nFndPos = STRING_NOTFOUND;
793 nPos = 0;
795 break;
796 default:
797 if( !bAlphaNum )
798 bAlphaNum = rCC.isLetterNumeric( rTxt, nPos );
802 if( STRING_NOTFOUND != nFndPos )
804 // ueber den gefundenen Bereich das Attribut aufspannen und
805 // das gefunde und am Ende stehende Zeichen loeschen
806 if( '*' == cInsChar ) // Fett
808 SvxWeightItem aSvxWeightItem( WEIGHT_BOLD, SID_ATTR_CHAR_WEIGHT );
809 rDoc.SetAttr( nFndPos + 1, nEndPos,
810 SID_ATTR_CHAR_WEIGHT,
811 aSvxWeightItem);
813 else // unterstrichen
815 SvxUnderlineItem aSvxUnderlineItem( UNDERLINE_SINGLE, SID_ATTR_CHAR_UNDERLINE );
816 rDoc.SetAttr( nFndPos + 1, nEndPos,
817 SID_ATTR_CHAR_UNDERLINE,
818 aSvxUnderlineItem);
820 rDoc.Delete( nEndPos, nEndPos + 1 );
821 rDoc.Delete( nFndPos, nFndPos + 1 );
824 return STRING_NOTFOUND != nFndPos;
828 BOOL SvxAutoCorrect::FnCptlSttSntnc( SvxAutoCorrDoc& rDoc,
829 const String& rTxt, BOOL bNormalPos,
830 xub_StrLen nSttPos, xub_StrLen nEndPos,
831 LanguageType eLang )
833 // Grossbuchstabe am Satz-Anfang ??
834 if( !rTxt.Len() || nEndPos <= nSttPos )
835 return FALSE;
837 CharClass& rCC = GetCharClass( eLang );
838 String aText( rTxt );
839 const sal_Unicode *pStart = aText.GetBuffer(),
840 *pStr = pStart + nEndPos,
841 *pWordStt = 0,
842 *pDelim = 0;
844 BOOL bAtStart = FALSE, bPrevPara = FALSE;
845 do {
846 --pStr;
847 if( rCC.isLetter(
848 aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) )
850 if( !pWordStt )
851 pDelim = pStr+1;
852 pWordStt = pStr;
854 else if( pWordStt &&
855 !rCC.isDigit(
856 aText,
857 sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) )
859 if( lcl_IsInAsciiArr( sImplWordChars, *pStr ) &&
860 pWordStt - 1 == pStr &&
861 // --> FME 2005-02-14 #i38971#
862 // l'intallazione at beginning of paragraph. Replaced < by <=
863 (long)(pStart + 1) <= (long)pStr &&
864 // <--
865 rCC.isLetter(
866 aText,
867 sal::static_int_cast< xub_StrLen >( pStr-1 - pStart ) ) )
868 pWordStt = --pStr;
869 else
870 break;
872 } while( 0 == ( bAtStart = (pStart == pStr)) );
875 if( !pWordStt ||
876 rCC.isDigit(
877 aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) ||
878 IsUpperLetter(
879 rCC.getCharacterType(
880 aText,
881 sal::static_int_cast< xub_StrLen >( pWordStt - pStart ) ) ) ||
882 0x1 == *pWordStt || 0x2 == *pWordStt )
883 return FALSE; // kein zu ersetzendes Zeichen, oder schon ok
885 // JP 27.10.97: wenn das Wort weniger als 3 Zeichen hat und der Trenner
886 // ein "Num"-Trenner ist, dann nicht ersetzen!
887 // Damit wird ein "a.", "a)", "a-a" nicht ersetzt!
888 if( *pDelim && 2 >= pDelim - pWordStt &&
889 lcl_IsInAsciiArr( ".-)>", *pDelim ) )
890 return FALSE;
892 if( !bAtStart ) // noch kein Absatz Anfang ?
894 if ( IsWordDelim( *pStr ) )
896 while( 0 == ( bAtStart = (pStart == pStr--) ) && IsWordDelim( *pStr ))
899 // Asian full stop, full width full stop, full width exclamation mark
900 // and full width question marks are treated as word delimiters
901 else if ( 0x3002 != *pStr && 0xFF0E != *pStr && 0xFF01 != *pStr &&
902 0xFF1F != *pStr )
903 return FALSE; // kein gueltiger Trenner -> keine Ersetzung
906 if( bAtStart ) // am Absatz Anfang ?
908 // Ueberpruefe den vorherigen Absatz, wenn es diesen gibt.
909 // Wenn ja, dann pruefe auf SatzTrenner am Ende.
910 const String* pPrevPara = rDoc.GetPrevPara( bNormalPos );
911 if( !pPrevPara )
913 // gueltiger Trenner -> Ersetze
914 String sChar( *pWordStt );
915 rCC.toUpper( sChar );
916 return sChar != *pWordStt &&
917 rDoc.Replace( xub_StrLen( pWordStt - pStart ), sChar );
920 aText = *pPrevPara;
921 bPrevPara = TRUE;
922 bAtStart = FALSE;
923 pStart = aText.GetBuffer();
924 pStr = pStart + aText.Len();
926 do { // alle Blanks ueberlesen
927 --pStr;
928 if( !IsWordDelim( *pStr ))
929 break;
930 } while( 0 == ( bAtStart = (pStart == pStr)) );
932 if( bAtStart )
933 return FALSE; // kein gueltiger Trenner -> keine Ersetzung
936 // bis hierhier wurde [ \t]+[A-Z0-9]+ gefunden. Test jetzt auf den
937 // Satztrenner. Es koennen alle 3 vorkommen, aber nicht mehrfach !!
938 const sal_Unicode* pExceptStt = 0;
939 if( !bAtStart )
941 BOOL bWeiter = TRUE;
942 int nFlag = C_NONE;
943 do {
944 switch( *pStr )
946 // Western and Asian full stop
947 case '.':
948 case 0x3002 :
949 case 0xFF0E :
951 if( nFlag & C_FULL_STOP )
952 return FALSE; // kein gueltiger Trenner -> keine Ersetzung
953 nFlag |= C_FULL_STOP;
954 pExceptStt = pStr;
956 break;
957 case '!':
958 case 0xFF01 :
960 if( nFlag & C_EXCLAMATION_MARK )
961 return FALSE; // kein gueltiger Trenner -> keine Ersetzung
962 nFlag |= C_EXCLAMATION_MARK;
964 break;
965 case '?':
966 case 0xFF1F :
968 if( nFlag & C_QUESTION_MARK)
969 return FALSE; // kein gueltiger Trenner -> keine Ersetzung
970 nFlag |= C_QUESTION_MARK;
972 break;
973 default:
974 if( !nFlag )
975 return FALSE; // kein gueltiger Trenner -> keine Ersetzung
976 else
977 bWeiter = FALSE;
978 break;
981 if( bWeiter && pStr-- == pStart )
983 // !!! wenn am Anfang, dann nie ersetzen.
984 // if( !nFlag )
985 return FALSE; // kein gueltiger Trenner -> keine Ersetzung
986 // ++pStr;
987 // break; // Schleife beenden
989 } while( bWeiter );
990 if( C_FULL_STOP != nFlag )
991 pExceptStt = 0;
994 if( 2 > ( pStr - pStart ) )
995 return FALSE;
997 if( !rCC.isLetterNumeric(
998 aText, sal::static_int_cast< xub_StrLen >( pStr-- - pStart ) ) )
1000 BOOL bValid = FALSE, bAlphaFnd = FALSE;
1001 const sal_Unicode* pTmpStr = pStr;
1002 while( !bValid )
1004 if( rCC.isDigit(
1005 aText,
1006 sal::static_int_cast< xub_StrLen >( pTmpStr - pStart ) ) )
1008 bValid = TRUE;
1009 pStr = pTmpStr - 1;
1011 else if( rCC.isLetter(
1012 aText,
1013 sal::static_int_cast< xub_StrLen >(
1014 pTmpStr - pStart ) ) )
1016 if( bAlphaFnd )
1018 bValid = TRUE;
1019 pStr = pTmpStr;
1021 else
1022 bAlphaFnd = TRUE;
1024 else if( bAlphaFnd || IsWordDelim( *pTmpStr ) )
1025 break;
1027 if( pTmpStr == pStart )
1028 break;
1030 --pTmpStr;
1033 if( !bValid )
1034 return FALSE; // kein gueltiger Trenner -> keine Ersetzung
1037 BOOL bNumericOnly = '0' <= *(pStr+1) && *(pStr+1) <= '9';
1039 // suche den Anfang vom Wort
1040 while( !IsWordDelim( *pStr ))
1042 if( bNumericOnly &&
1043 rCC.isLetter(
1044 aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) )
1045 bNumericOnly = FALSE;
1047 if( pStart == pStr )
1048 break;
1050 --pStr;
1053 if( bNumericOnly ) // besteht nur aus Zahlen, dann nicht
1054 return FALSE;
1056 if( IsWordDelim( *pStr ))
1057 ++pStr;
1059 String sWord;
1061 // ueberpruefe anhand der Exceptionliste
1062 if( pExceptStt )
1064 sWord = String(
1065 pStr, sal::static_int_cast< xub_StrLen >( pExceptStt - pStr + 1 ) );
1066 if( FindInCplSttExceptList(eLang, sWord) )
1067 return FALSE;
1069 // loesche alle nicht alpanum. Zeichen am Wortanfang/-ende und
1070 // teste dann noch mal ( erkennt: "(min.", "/min.", usw.)
1071 String sTmp( sWord );
1072 while( sTmp.Len() &&
1073 !rCC.isLetterNumeric( sTmp, 0 ) )
1074 sTmp.Erase( 0, 1 );
1076 // alle hinteren nicht alphanumerische Zeichen bis auf das
1077 // Letzte entfernen
1078 xub_StrLen nLen = sTmp.Len();
1079 while( nLen && !rCC.isLetterNumeric( sTmp, nLen-1 ) )
1080 --nLen;
1081 if( nLen + 1 < sTmp.Len() )
1082 sTmp.Erase( nLen + 1 );
1084 if( sTmp.Len() && sTmp.Len() != sWord.Len() &&
1085 FindInCplSttExceptList(eLang, sTmp))
1086 return FALSE;
1088 if(FindInCplSttExceptList(eLang, sWord, TRUE))
1089 return FALSE;
1092 // Ok, dann ersetze mal
1093 sal_Unicode cSave = *pWordStt;
1094 nSttPos = sal::static_int_cast< xub_StrLen >( pWordStt - rTxt.GetBuffer() );
1095 String sChar( cSave );
1096 rCC.toUpper( sChar );
1097 BOOL bRet = sChar.GetChar(0) != cSave && rDoc.Replace( nSttPos, sChar );
1099 // das Wort will vielleicht jemand haben
1100 if( bRet && SaveWordCplSttLst & nFlags )
1101 rDoc.SaveCpltSttWord( CptlSttSntnc, nSttPos, sWord, cSave );
1103 return bRet;
1106 bool SvxAutoCorrect::FnCorrectCapsLock( SvxAutoCorrDoc& rDoc, const String& rTxt,
1107 xub_StrLen nSttPos, xub_StrLen nEndPos,
1108 LanguageType eLang )
1110 if (nEndPos - nSttPos < 2)
1111 // string must be at least 2-character long.
1112 return false;
1114 CharClass& rCC = GetCharClass( eLang );
1116 // Check the first 2 letters.
1117 if ( !IsLowerLetter(rCC.getCharacterType(rTxt, nSttPos)) )
1118 return false;
1120 if ( !IsUpperLetter(rCC.getCharacterType(rTxt, nSttPos+1)) )
1121 return false;
1123 String aConverted;
1124 aConverted.Append( rCC.upper(rTxt.GetChar(nSttPos)) );
1125 aConverted.Append( rCC.lower(rTxt.GetChar(nSttPos+1)) );
1127 for (xub_StrLen i = nSttPos+2; i < nEndPos; ++i)
1129 if ( IsLowerLetter(rCC.getCharacterType(rTxt, i)) )
1130 // A lowercase letter disqualifies the whole text.
1131 return false;
1133 if ( IsUpperLetter(rCC.getCharacterType(rTxt, i)) )
1134 // Another uppercase letter. Convert it.
1135 aConverted.Append( rCC.lower(rTxt.GetChar(i)) );
1136 else
1137 // This is not an alphabetic letter. Leave it as-is.
1138 aConverted.Append(rTxt.GetChar(i));
1141 // Replace the word.
1142 rDoc.Delete(nSttPos, nEndPos);
1143 rDoc.Insert(nSttPos, aConverted);
1145 return true;
1148 //The method below is renamed from _GetQuote to GetQuote by BerryJia for Bug95846 Time:2002-8-13 15:50
1149 sal_Unicode SvxAutoCorrect::GetQuote( sal_Unicode cInsChar, BOOL bSttQuote,
1150 LanguageType eLang ) const
1152 sal_Unicode cRet = bSttQuote ? ( '\"' == cInsChar
1153 ? GetStartDoubleQuote()
1154 : GetStartSingleQuote() )
1155 : ( '\"' == cInsChar
1156 ? GetEndDoubleQuote()
1157 : GetEndSingleQuote() );
1158 if( !cRet )
1160 // dann ueber die Language das richtige Zeichen heraussuchen
1161 if( LANGUAGE_NONE == eLang )
1162 cRet = cInsChar;
1163 else
1165 LocaleDataWrapper& rLcl = GetLocaleDataWrapper( eLang );
1166 String sRet( bSttQuote
1167 ? ( '\"' == cInsChar
1168 ? rLcl.getDoubleQuotationMarkStart()
1169 : rLcl.getQuotationMarkStart() )
1170 : ( '\"' == cInsChar
1171 ? rLcl.getDoubleQuotationMarkEnd()
1172 : rLcl.getQuotationMarkEnd() ));
1173 cRet = sRet.Len() ? sRet.GetChar( 0 ) : cInsChar;
1176 return cRet;
1179 void SvxAutoCorrect::InsertQuote( SvxAutoCorrDoc& rDoc, xub_StrLen nInsPos,
1180 sal_Unicode cInsChar, BOOL bSttQuote,
1181 BOOL bIns )
1183 LanguageType eLang = rDoc.GetLanguage( nInsPos, FALSE );
1184 sal_Unicode cRet = GetQuote( cInsChar, bSttQuote, eLang );
1186 //JP 13.02.99: damit beim Undo das "einfuegte" Zeichen wieder erscheint,
1187 // wird es erstmal eingefuegt und dann ueberschrieben
1188 String sChg( cInsChar );
1189 if( bIns )
1190 rDoc.Insert( nInsPos, sChg );
1191 else
1192 rDoc.Replace( nInsPos, sChg );
1194 //JP 13.08.97: Bug 42477 - bei doppelten Anfuehrungszeichen muss bei
1195 // franzoesischer Sprache an Anfang ein Leerzeichen dahinter
1196 // und am Ende ein Leerzeichen dahinter eingefuegt werden.
1197 sChg = cRet;
1199 if( '\"' == cInsChar )
1201 if( LANGUAGE_SYSTEM == eLang )
1202 eLang = GetAppLang();
1203 switch( eLang )
1205 case LANGUAGE_FRENCH:
1206 case LANGUAGE_FRENCH_BELGIAN:
1207 case LANGUAGE_FRENCH_CANADIAN:
1208 case LANGUAGE_FRENCH_SWISS:
1209 case LANGUAGE_FRENCH_LUXEMBOURG:
1210 // JP 09.02.99: das zusaetzliche Zeichen immer per Insert einfuegen.
1211 // Es ueberschreibt nichts!
1213 String s( static_cast< sal_Unicode >(0xA0) );
1214 // UNICODE code for no break space
1215 if( rDoc.Insert( bSttQuote ? nInsPos+1 : nInsPos, s ))
1217 if( !bSttQuote )
1218 ++nInsPos;
1221 break;
1225 rDoc.Replace( nInsPos, sChg );
1228 String SvxAutoCorrect::GetQuote( SvxAutoCorrDoc& rDoc, xub_StrLen nInsPos,
1229 sal_Unicode cInsChar, BOOL bSttQuote )
1231 LanguageType eLang = rDoc.GetLanguage( nInsPos, FALSE );
1232 sal_Unicode cRet = GetQuote( cInsChar, bSttQuote, eLang );
1234 String sRet( cRet );
1235 //JP 13.08.97: Bug 42477 - bei doppelten Anfuehrungszeichen muss bei
1236 // franzoesischer Sprache an Anfang ein Leerzeichen dahinter
1237 // und am Ende ein Leerzeichen dahinter eingefuegt werden.
1238 if( '\"' == cInsChar )
1240 if( LANGUAGE_SYSTEM == eLang )
1241 eLang = GetAppLang();
1242 switch( eLang )
1244 case LANGUAGE_FRENCH:
1245 case LANGUAGE_FRENCH_BELGIAN:
1246 case LANGUAGE_FRENCH_CANADIAN:
1247 case LANGUAGE_FRENCH_SWISS:
1248 case LANGUAGE_FRENCH_LUXEMBOURG:
1249 if( bSttQuote )
1250 sRet += ' ';
1251 else
1252 sRet.Insert( ' ', 0 );
1253 break;
1256 return sRet;
1259 ULONG SvxAutoCorrect::AutoCorrect( SvxAutoCorrDoc& rDoc, const String& rTxt,
1260 xub_StrLen nInsPos, sal_Unicode cChar,
1261 BOOL bInsert, Window* pFrameWin )
1263 ULONG nRet = 0;
1264 do{ // only for middle check loop !!
1265 if( cChar )
1267 //JP 10.02.97: doppelte Spaces verhindern
1268 if( nInsPos && ' ' == cChar &&
1269 IsAutoCorrFlag( IngnoreDoubleSpace ) &&
1270 ' ' == rTxt.GetChar( nInsPos - 1 ) )
1272 nRet = IngnoreDoubleSpace;
1273 break;
1276 BOOL bSingle = '\'' == cChar;
1277 BOOL bIsReplaceQuote =
1278 (IsAutoCorrFlag( ChgQuotes ) && ('\"' == cChar )) ||
1279 (IsAutoCorrFlag( ChgSglQuotes ) && bSingle );
1280 if( bIsReplaceQuote )
1282 sal_Unicode cPrev;
1283 BOOL bSttQuote = !nInsPos ||
1284 IsWordDelim( ( cPrev = rTxt.GetChar( nInsPos-1 ))) ||
1285 // os: #56034# - Warum kein schliessendes Anfuehrungszeichen nach dem Bindestrich?
1286 // strchr( "-([{", cPrev ) ||
1287 lcl_IsInAsciiArr( "([{", cPrev ) ||
1288 ( cEmDash && cEmDash == cPrev ) ||
1289 ( cEnDash && cEnDash == cPrev );
1291 InsertQuote( rDoc, nInsPos, cChar, bSttQuote, bInsert );
1292 nRet = bSingle ? ChgSglQuotes : ChgQuotes;
1293 break;
1296 if( bInsert )
1297 rDoc.Insert( nInsPos, cChar );
1298 else
1299 rDoc.Replace( nInsPos, cChar );
1302 if( !nInsPos )
1303 break;
1305 xub_StrLen nPos = nInsPos - 1;
1307 // Bug 19286: nur direkt hinter dem "Wort" aufsetzen
1308 if( IsWordDelim( rTxt.GetChar( nPos )))
1309 break;
1311 // automatisches Fett oder Unterstreichen setzen?
1312 if( '*' == cChar || '_' == cChar )
1314 if( IsAutoCorrFlag( ChgWeightUnderl ) &&
1315 FnChgWeightUnderl( rDoc, rTxt, 0, nPos+1 ) )
1316 nRet = ChgWeightUnderl;
1317 break;
1320 while( nPos && !IsWordDelim( rTxt.GetChar( --nPos )))
1323 // Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort
1324 // Kuerzel im Auto
1325 xub_StrLen nCapLttrPos = nPos+1; // auf das 1. Zeichen
1326 if( !nPos && !IsWordDelim( rTxt.GetChar( 0 )))
1327 --nCapLttrPos; // Absatz Anfang und kein Blank !
1329 LanguageType eLang = rDoc.GetLanguage( nCapLttrPos, FALSE );
1330 if( LANGUAGE_SYSTEM == eLang )
1331 eLang = MsLangId::getSystemLanguage();
1332 CharClass& rCC = GetCharClass( eLang );
1334 // Bug 19285: Symbolzeichen nicht anfassen
1335 if( lcl_IsSymbolChar( rCC, rTxt, nCapLttrPos, nInsPos ))
1336 break;
1338 if( IsAutoCorrFlag( Autocorrect ) )
1340 const String* pPara = 0;
1341 const String** ppPara = IsAutoCorrFlag(CptlSttSntnc) ? &pPara : 0;
1343 BOOL bChgWord = rDoc.ChgAutoCorrWord( nCapLttrPos, nInsPos,
1344 *this, ppPara );
1345 if( !bChgWord )
1347 // JP 16.06.98: dann versuche mal alle !AlphaNum. Zeichen los zu
1348 // werden und teste dann nochmals
1349 //JP 22.04.99: Bug 63883 - entferne nur die "Klammern Start/-Anfaenge",
1350 // alle anderen Zeichen muessen drin bleiben.
1351 xub_StrLen nCapLttrPos1 = nCapLttrPos, nInsPos1 = nInsPos;
1352 while( nCapLttrPos1 < nInsPos &&
1353 lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nCapLttrPos1 ) )
1355 ++nCapLttrPos1;
1356 while( nCapLttrPos1 < nInsPos1 && nInsPos1 &&
1357 lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nInsPos1-1 ) )
1359 --nInsPos1;
1361 if( (nCapLttrPos1 != nCapLttrPos || nInsPos1 != nInsPos ) &&
1362 nCapLttrPos1 < nInsPos1 &&
1363 rDoc.ChgAutoCorrWord( nCapLttrPos1, nInsPos1, *this, ppPara ))
1365 bChgWord = TRUE;
1366 nCapLttrPos = nCapLttrPos1;
1370 if( bChgWord )
1372 nRet = Autocorrect;
1373 if( pPara )
1375 xub_StrLen nEnd = nCapLttrPos;
1376 while( nEnd < pPara->Len() &&
1377 !IsWordDelim( pPara->GetChar( nEnd )))
1378 ++nEnd;
1380 // Grossbuchstabe am Satz-Anfang ??
1381 if( IsAutoCorrFlag( CptlSttSntnc ) &&
1382 FnCptlSttSntnc( rDoc, *pPara, FALSE,
1383 nCapLttrPos, nEnd, eLang ) )
1384 nRet |= CptlSttSntnc;
1386 if( IsAutoCorrFlag( ChgToEnEmDash ) &&
1387 FnChgToEnEmDash( rDoc, rTxt, nCapLttrPos, nEnd, eLang ) )
1388 nRet |= ChgToEnEmDash;
1390 break;
1394 if( ( IsAutoCorrFlag( nRet = ChgFractionSymbol ) &&
1395 FnChgFractionSymbol( rDoc, rTxt, nCapLttrPos, nInsPos ) ) ||
1396 ( IsAutoCorrFlag( nRet = ChgOrdinalNumber ) &&
1397 FnChgOrdinalNumber( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) ||
1398 ( IsAutoCorrFlag( nRet = AddNonBrkSpace ) &&
1399 FnAddNonBrkSpace( rDoc, rTxt, nCapLttrPos, nInsPos - 1, eLang ) ) ||
1400 ( IsAutoCorrFlag( nRet = SetINetAttr ) &&
1401 ( ' ' == cChar || '\t' == cChar || 0x0a == cChar || !cChar ) &&
1402 FnSetINetAttr( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) )
1404 else
1406 bool bLockKeyOn = pFrameWin && (pFrameWin->GetIndicatorState() & INDICATOR_CAPSLOCK);
1408 nRet = 0;
1409 if ( bLockKeyOn && IsAutoCorrFlag( CorrectCapsLock ) &&
1410 FnCorrectCapsLock( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) )
1412 // Correct accidental use of cAPS LOCK key (do this only when
1413 // the caps or shift lock key is pressed). Turn off the caps
1414 // lock afterwords.
1415 nRet |= CorrectCapsLock;
1416 pFrameWin->SimulateKeyPress( KEY_CAPSLOCK );
1419 // Grossbuchstabe am Satz-Anfang ??
1420 if( IsAutoCorrFlag( CptlSttSntnc ) &&
1421 FnCptlSttSntnc( rDoc, rTxt, TRUE, nCapLttrPos, nInsPos, eLang ) )
1422 nRet |= CptlSttSntnc;
1424 // Zwei Grossbuchstaben am Wort-Anfang ??
1425 if( IsAutoCorrFlag( CptlSttWrd ) &&
1426 FnCptlSttWrd( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) )
1427 nRet |= CptlSttWrd;
1429 if( IsAutoCorrFlag( ChgToEnEmDash ) &&
1430 FnChgToEnEmDash( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) )
1431 nRet |= ChgToEnEmDash;
1434 } while( FALSE );
1436 SfxViewFrame* pVFrame;
1437 if( nRet && 0 != (pVFrame = SfxViewFrame::Current()) &&
1438 pVFrame->GetFrame() )
1440 ULONG nHelpId = 0;
1441 if( nRet & ( Autocorrect|CptlSttSntnc|CptlSttWrd|ChgToEnEmDash ) )
1443 // von 0 - 15
1444 if( nRet & ChgToEnEmDash )
1445 nHelpId += 8;
1446 if( nRet & Autocorrect )
1447 nHelpId += 4;
1448 if( nRet & CptlSttSntnc )
1449 nHelpId += 2;
1450 if( nRet & CptlSttWrd )
1451 nHelpId += 1;
1453 else
1455 if( nRet & ChgQuotes) nHelpId = 16;
1456 else if( nRet & ChgSglQuotes) nHelpId = 17;
1457 else if( nRet & SetINetAttr) nHelpId = 18;
1458 else if( nRet & IngnoreDoubleSpace) nHelpId = 19;
1459 else if( nRet & ChgWeightUnderl) nHelpId = 20;
1460 else if( nRet & ChgFractionSymbol ) nHelpId = 21;
1461 else if( nRet & ChgOrdinalNumber) nHelpId = 22;
1464 DBG_ASSERT( nHelpId && nHelpId < (HID_AUTOCORR_HELP_END -
1465 HID_AUTOCORR_HELP_START + 1),
1466 "wrong HelpId Range" );
1468 if( nHelpId )
1470 nHelpId += HID_AUTOCORR_HELP_START - 1;
1471 SfxHelp::OpenHelpAgent( pVFrame->GetFrame(), nHelpId );
1476 return nRet;
1479 SvxAutoCorrectLanguageLists& SvxAutoCorrect::_GetLanguageList(
1480 LanguageType eLang )
1482 if( !pLangTable->IsKeyValid( ULONG( eLang )))
1483 CreateLanguageFile( eLang, TRUE);
1484 return *pLangTable->Seek( ULONG( eLang ) );
1487 void SvxAutoCorrect::SaveCplSttExceptList( LanguageType eLang )
1489 if( pLangTable->IsKeyValid( ULONG( eLang )))
1491 SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(ULONG(eLang));
1492 if( pLists )
1493 pLists->SaveCplSttExceptList();
1495 #ifndef PRODUCT
1496 else
1498 DBG_ERROR("speichern einer leeren Liste?");
1500 #endif
1503 void SvxAutoCorrect::SaveWrdSttExceptList(LanguageType eLang)
1505 if(pLangTable->IsKeyValid(ULONG(eLang)))
1507 SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(ULONG(eLang));
1508 if(pLists)
1509 pLists->SaveWrdSttExceptList();
1511 #ifndef PRODUCT
1512 else
1514 DBG_ERROR("speichern einer leeren Liste?");
1516 #endif
1520 // fuegt ein einzelnes Wort hinzu. Die Liste wird sofort
1521 // in die Datei geschrieben!
1522 BOOL SvxAutoCorrect::AddCplSttException( const String& rNew,
1523 LanguageType eLang )
1525 SvxAutoCorrectLanguageListsPtr pLists = 0;
1526 //entweder die richtige Sprache ist vorhanden oder es kommt in die allg. Liste
1527 if( pLangTable->IsKeyValid(ULONG(eLang)))
1528 pLists = pLangTable->Seek(ULONG(eLang));
1529 else if(pLangTable->IsKeyValid(ULONG(LANGUAGE_DONTKNOW))||
1530 CreateLanguageFile(LANGUAGE_DONTKNOW, TRUE))
1532 pLists = pLangTable->Seek(ULONG(LANGUAGE_DONTKNOW));
1534 DBG_ASSERT(pLists, "keine Autokorrekturdatei");
1535 return pLists->AddToCplSttExceptList(rNew);
1539 // fuegt ein einzelnes Wort hinzu. Die Liste wird sofort
1540 // in die Datei geschrieben!
1541 BOOL SvxAutoCorrect::AddWrtSttException( const String& rNew,
1542 LanguageType eLang )
1544 SvxAutoCorrectLanguageListsPtr pLists = 0;
1545 //entweder die richtige Sprache ist vorhanden oder es kommt in die allg. Liste
1546 if(pLangTable->IsKeyValid(ULONG(eLang)))
1547 pLists = pLangTable->Seek(ULONG(eLang));
1548 else if(pLangTable->IsKeyValid(ULONG(LANGUAGE_DONTKNOW))||
1549 CreateLanguageFile(LANGUAGE_DONTKNOW, TRUE))
1550 pLists = pLangTable->Seek(ULONG(LANGUAGE_DONTKNOW));
1551 DBG_ASSERT(pLists, "keine Autokorrekturdatei");
1552 return pLists->AddToWrdSttExceptList(rNew);
1558 void SvxAutoCorrect::SetUserAutoCorrFileName( const String& rNew )
1560 if( sUserAutoCorrFile != rNew )
1562 sUserAutoCorrFile = rNew;
1564 // sind die Listen gesetzt sind, so muessen sie jetzt geloescht
1565 // werden
1566 lcl_ClearTable(*pLangTable);
1567 nFlags &= ~(CplSttLstLoad | WrdSttLstLoad | ChgWordLstLoad );
1571 void SvxAutoCorrect::SetShareAutoCorrFileName( const String& rNew )
1573 if( sShareAutoCorrFile != rNew )
1575 sShareAutoCorrFile = rNew;
1577 // sind die Listen gesetzt sind, so muessen sie jetzt geloescht
1578 // werden
1579 lcl_ClearTable(*pLangTable);
1580 nFlags &= ~(CplSttLstLoad | WrdSttLstLoad | ChgWordLstLoad );
1585 BOOL SvxAutoCorrect::GetPrevAutoCorrWord( SvxAutoCorrDoc& rDoc,
1586 const String& rTxt, xub_StrLen nPos,
1587 String& rWord ) const
1589 if( !nPos )
1590 return FALSE;
1592 xub_StrLen nEnde = nPos;
1594 // dahinter muss ein Blank oder Tab folgen!
1595 if( ( nPos < rTxt.Len() &&
1596 !IsWordDelim( rTxt.GetChar( nPos ))) ||
1597 IsWordDelim( rTxt.GetChar( --nPos )))
1598 return FALSE;
1600 while( nPos && !IsWordDelim( rTxt.GetChar( --nPos )))
1603 // Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort
1604 // Kuerzel im Auto
1605 xub_StrLen nCapLttrPos = nPos+1; // auf das 1. Zeichen
1606 if( !nPos && !IsWordDelim( rTxt.GetChar( 0 )))
1607 --nCapLttrPos; // Absatz Anfang und kein Blank !
1609 while( lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nCapLttrPos )) )
1610 if( ++nCapLttrPos >= nEnde )
1611 return FALSE;
1613 // Bug 19285: Symbolzeichen nicht anfassen
1614 // Interresant erst ab 3 Zeichen
1615 if( 3 > nEnde - nCapLttrPos )
1616 return FALSE;
1618 LanguageType eLang = rDoc.GetLanguage( nCapLttrPos, FALSE );
1619 if( LANGUAGE_SYSTEM == eLang )
1620 eLang = MsLangId::getSystemLanguage();
1622 SvxAutoCorrect* pThis = (SvxAutoCorrect*)this;
1623 CharClass& rCC = pThis->GetCharClass( eLang );
1625 if( lcl_IsSymbolChar( rCC, rTxt, nCapLttrPos, nEnde ))
1626 return FALSE;
1628 rWord = rTxt.Copy( nCapLttrPos, nEnde - nCapLttrPos );
1629 return TRUE;
1632 BOOL SvxAutoCorrect::CreateLanguageFile( LanguageType eLang, BOOL bNewFile )
1634 DBG_ASSERT(!pLangTable->IsKeyValid(ULONG(eLang)), "Sprache ist bereits vorhanden");
1636 String sUserDirFile( GetAutoCorrFileName( eLang, TRUE, FALSE )),
1637 sShareDirFile( sUserDirFile );
1638 SvxAutoCorrectLanguageListsPtr pLists = 0;
1640 Time nMinTime( 0, 2 ), nAktTime, nLastCheckTime;
1641 ULONG nFndPos;
1642 if( TABLE_ENTRY_NOTFOUND !=
1643 pLastFileTable->SearchKey( ULONG( eLang ), &nFndPos ) &&
1644 ( nLastCheckTime.SetTime( pLastFileTable->GetObject( nFndPos )),
1645 nLastCheckTime < nAktTime ) &&
1646 ( nAktTime - nLastCheckTime ) < nMinTime )
1648 // no need to test the file, because the last check is not older then
1649 // 2 minutes.
1650 if( bNewFile )
1652 sShareDirFile = sUserDirFile;
1653 pLists = new SvxAutoCorrectLanguageLists( *this, sShareDirFile,
1654 sUserDirFile, eLang );
1655 pLangTable->Insert( ULONG(eLang), pLists );
1656 pLastFileTable->Remove( ULONG( eLang ) );
1659 else if( ( FStatHelper::IsDocument( sUserDirFile ) ||
1660 FStatHelper::IsDocument( sShareDirFile =
1661 GetAutoCorrFileName( eLang, FALSE, FALSE ) ) ) ||
1662 ( sShareDirFile = sUserDirFile, bNewFile ))
1664 pLists = new SvxAutoCorrectLanguageLists( *this, sShareDirFile,
1665 sUserDirFile, eLang );
1666 pLangTable->Insert( ULONG(eLang), pLists );
1667 pLastFileTable->Remove( ULONG( eLang ) );
1669 else if( !bNewFile )
1671 if( !pLastFileTable->Insert( ULONG( eLang ), nAktTime.GetTime() ))
1672 pLastFileTable->Replace( ULONG( eLang ), nAktTime.GetTime() );
1674 return pLists != 0;
1677 BOOL SvxAutoCorrect::PutText( const String& rShort, const String& rLong,
1678 LanguageType eLang )
1680 BOOL bRet = FALSE;
1681 if( pLangTable->IsKeyValid( ULONG(eLang)) || CreateLanguageFile(eLang) )
1682 bRet = pLangTable->Seek( ULONG(eLang) )->PutText(rShort, rLong);
1683 return bRet;
1687 // - loesche einen Eintrag
1688 BOOL SvxAutoCorrect::DeleteText( const String& rShort, LanguageType eLang )
1690 BOOL bRet = FALSE;
1691 if( pLangTable->IsKeyValid( ULONG( eLang )) )
1692 bRet = pLangTable->Seek( ULONG( eLang ))->DeleteText( rShort );
1693 return bRet;
1697 // - return den Ersetzungstext (nur fuer SWG-Format, alle anderen
1698 // koennen aus der Wortliste herausgeholt werden!)
1699 BOOL SvxAutoCorrect::GetLongText( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >&, const String&, const String& , String& )
1701 return FALSE;
1704 // - Text mit Attributierung (kann nur der SWG - SWG-Format!)
1705 BOOL SvxAutoCorrect::PutText( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >&, const String&, const String&, SfxObjectShell&,
1706 String& )
1708 return FALSE;
1711 void EncryptBlockName_Imp( String& rName )
1713 xub_StrLen nLen, nPos = 1;
1714 rName.Insert( '#', 0 );
1715 sal_Unicode* pName = rName.GetBufferAccess();
1716 for ( nLen = rName.Len(), ++pName; nPos < nLen; ++nPos, ++pName )
1718 if( lcl_IsInAsciiArr( "!/:.\\", *pName ))
1719 *pName &= 0x0f;
1723 /* This code is copied from SwXMLTextBlocks::GeneratePackageName */
1724 void GeneratePackageName ( const String& rShort, String& rPackageName )
1726 rPackageName = rShort;
1727 xub_StrLen nPos = 0;
1728 sal_Unicode pDelims[] = { '!', '/', ':', '.', '\\', 0 };
1729 ByteString sByte ( rPackageName, RTL_TEXTENCODING_UTF7);
1730 rPackageName = String (sByte, RTL_TEXTENCODING_ASCII_US);
1731 while( STRING_NOTFOUND != ( nPos = rPackageName.SearchChar( pDelims, nPos )))
1733 rPackageName.SetChar( nPos, '_' );
1734 ++nPos;
1738 void DecryptBlockName_Imp( String& rName )
1740 if( '#' == rName.GetChar( 0 ) )
1742 rName.Erase( 0, 1 );
1743 sal_Unicode* pName = rName.GetBufferAccess();
1744 xub_StrLen nLen, nPos;
1745 for ( nLen = rName.Len(), nPos = 0; nPos < nLen; ++nPos, ++pName )
1746 switch( *pName )
1748 case 0x01: *pName = '!'; break;
1749 case 0x0A: *pName = ':'; break;
1750 case 0x0C: *pName = '\\'; break;
1751 case 0x0E: *pName = '.'; break;
1752 case 0x0F: *pName = '/'; break;
1758 /* -----------------18.11.98 16:00-------------------
1760 * --------------------------------------------------*/
1761 const SvxAutocorrWord* lcl_SearchWordsInList(
1762 SvxAutoCorrectLanguageListsPtr pList, const String& rTxt,
1763 xub_StrLen& rStt, xub_StrLen nEndPos, SvxAutoCorrDoc& )
1765 const SvxAutocorrWordList* pAutoCorrWordList = pList->GetAutocorrWordList();
1766 TransliterationWrapper& rCmp = GetIgnoreTranslWrapper();
1767 for( xub_StrLen nPos = 0; nPos < pAutoCorrWordList->Count(); ++nPos )
1769 const SvxAutocorrWord* pFnd = (*pAutoCorrWordList)[ nPos ];
1770 const String& rChk = pFnd->GetShort();
1771 if( nEndPos >= rChk.Len() )
1773 xub_StrLen nCalcStt = nEndPos - rChk.Len();
1774 if( ( !nCalcStt || nCalcStt == rStt ||
1775 ( nCalcStt < rStt &&
1776 IsWordDelim( rTxt.GetChar(nCalcStt - 1 ) ))) )
1778 String sWord( rTxt.GetBuffer() + nCalcStt, rChk.Len() );
1779 if( rCmp.isEqual( rChk, sWord ))
1781 rStt = nCalcStt;
1782 return pFnd;
1787 return 0;
1791 // suche das oder die Worte in der ErsetzungsTabelle
1792 const SvxAutocorrWord* SvxAutoCorrect::SearchWordsInList(
1793 const String& rTxt, xub_StrLen& rStt, xub_StrLen nEndPos,
1794 SvxAutoCorrDoc& rDoc, LanguageType& rLang )
1796 LanguageType eLang = rLang;
1797 const SvxAutocorrWord* pRet = 0;
1798 if( LANGUAGE_SYSTEM == eLang )
1799 eLang = MsLangId::getSystemLanguage();
1801 // zuerst nach eLang suchen, dann nach der Obersprache
1802 // US-Englisch -> Englisch und zuletzt in LANGUAGE_DONTKNOW
1804 if( pLangTable->IsKeyValid( ULONG( eLang ) ) ||
1805 CreateLanguageFile( eLang, FALSE ))
1807 //die Sprache ist vorhanden - also her damit
1808 SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(ULONG(eLang));
1809 pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos, rDoc );
1810 if( pRet )
1812 rLang = eLang;
1813 return pRet;
1817 // wenn es hier noch nicht gefunden werden konnte, dann weitersuchen
1818 ULONG nTmpKey1 = eLang & 0x7ff, // die Hauptsprache in vielen Faellen u.B. DE
1819 nTmpKey2 = eLang & 0x3ff, // sonst z.B. EN
1820 nTmp;
1822 if( ((nTmp = nTmpKey1) != (ULONG)eLang &&
1823 ( pLangTable->IsKeyValid( nTmpKey1 ) ||
1824 CreateLanguageFile( LanguageType( nTmpKey1 ), FALSE ) )) ||
1825 (( nTmp = nTmpKey2) != (ULONG)eLang &&
1826 ( pLangTable->IsKeyValid( nTmpKey2 ) ||
1827 CreateLanguageFile( LanguageType( nTmpKey2 ), FALSE ) )) )
1829 //die Sprache ist vorhanden - also her damit
1830 SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek( nTmp );
1831 pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos, rDoc);
1832 if( pRet )
1834 rLang = LanguageType( nTmp );
1835 return pRet;
1838 if( pLangTable->IsKeyValid( ULONG( LANGUAGE_DONTKNOW ) ) ||
1839 CreateLanguageFile( LANGUAGE_DONTKNOW, FALSE ) )
1841 //die Sprache ist vorhanden - also her damit
1842 SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(ULONG(LANGUAGE_DONTKNOW));
1843 pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos, rDoc);
1844 if( pRet )
1846 rLang = LANGUAGE_DONTKNOW;
1847 return pRet;
1850 return 0;
1852 /* -----------------18.11.98 13:46-------------------
1854 * --------------------------------------------------*/
1855 BOOL SvxAutoCorrect::FindInWrdSttExceptList( LanguageType eLang,
1856 const String& sWord )
1858 //zuerst nach eLang suchen, dann nach der Obersprace US-Englisch -> Englisch
1859 //und zuletzt in LANGUAGE_DONTKNOW
1860 ULONG nTmpKey1 = eLang & 0x7ff; // die Hauptsprache in vielen Faellen u.B. DE
1861 ULONG nTmpKey2 = eLang & 0x3ff; // sonst z.B. EN
1862 String sTemp(sWord);
1863 if( pLangTable->IsKeyValid( ULONG( eLang )) ||
1864 CreateLanguageFile( eLang, FALSE ) )
1866 //die Sprache ist vorhanden - also her damit
1867 SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(ULONG(eLang));
1868 String _sTemp(sWord);
1869 if(pList->GetWrdSttExceptList()->Seek_Entry(&_sTemp))
1870 return TRUE;
1873 // wenn es hier noch nicht gefunden werden konnte, dann weitersuchen
1874 ULONG nTmp;
1875 if( ((nTmp = nTmpKey1) != (ULONG)eLang &&
1876 ( pLangTable->IsKeyValid( nTmpKey1 ) ||
1877 CreateLanguageFile( LanguageType( nTmpKey1 ), FALSE ) )) ||
1878 (( nTmp = nTmpKey2) != (ULONG)eLang &&
1879 ( pLangTable->IsKeyValid( nTmpKey2 ) ||
1880 CreateLanguageFile( LanguageType( nTmpKey2 ), FALSE ) )) )
1882 //die Sprache ist vorhanden - also her damit
1883 SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(nTmp);
1884 if(pList->GetWrdSttExceptList()->Seek_Entry(&sTemp))
1885 return TRUE;
1887 if(pLangTable->IsKeyValid(ULONG(LANGUAGE_DONTKNOW))|| CreateLanguageFile(LANGUAGE_DONTKNOW, FALSE))
1889 //die Sprache ist vorhanden - also her damit
1890 SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(ULONG(LANGUAGE_DONTKNOW));
1891 if(pList->GetWrdSttExceptList()->Seek_Entry(&sTemp))
1892 return TRUE;
1894 return FALSE;
1896 /* -----------------18.11.98 14:28-------------------
1898 * --------------------------------------------------*/
1899 BOOL lcl_FindAbbreviation( const SvStringsISortDtor* pList, const String& sWord)
1901 String sAbk( '~' );
1902 USHORT nPos;
1903 pList->Seek_Entry( &sAbk, &nPos );
1904 if( nPos < pList->Count() )
1906 String sLowerWord( sWord ); sLowerWord.ToLowerAscii();
1907 const String* pAbk;
1908 for( USHORT n = nPos;
1909 n < pList->Count() &&
1910 '~' == ( pAbk = (*pList)[ n ])->GetChar( 0 );
1911 ++n )
1913 // ~ und ~. sind nicht erlaubt!
1914 if( 2 < pAbk->Len() && pAbk->Len() - 1 <= sWord.Len() )
1916 String sLowerAbk( *pAbk ); sLowerAbk.ToLowerAscii();
1917 for( xub_StrLen i = sLowerAbk.Len(), ii = sLowerWord.Len(); i; )
1919 if( !--i ) // stimmt ueberein
1920 return TRUE;
1922 if( sLowerAbk.GetChar( i ) != sLowerWord.GetChar( --ii ))
1923 break;
1928 DBG_ASSERT( !(nPos && '~' == (*pList)[ --nPos ]->GetChar( 0 ) ),
1929 "falsch sortierte ExeptionListe?" );
1930 return FALSE;
1932 /* -----------------18.11.98 14:49-------------------
1934 * --------------------------------------------------*/
1935 BOOL SvxAutoCorrect::FindInCplSttExceptList(LanguageType eLang,
1936 const String& sWord, BOOL bAbbreviation)
1938 //zuerst nach eLang suchen, dann nach der Obersprace US-Englisch -> Englisch
1939 //und zuletzt in LANGUAGE_DONTKNOW
1940 ULONG nTmpKey1 = eLang & 0x7ff; // die Hauptsprache in vielen Faellen u.B. DE
1941 ULONG nTmpKey2 = eLang & 0x3ff; // sonst z.B. EN
1942 String sTemp( sWord );
1943 if( pLangTable->IsKeyValid( ULONG( eLang )) ||
1944 CreateLanguageFile( eLang, FALSE ))
1946 //die Sprache ist vorhanden - also her damit
1947 SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(ULONG(eLang));
1948 const SvStringsISortDtor* pList = pLists->GetCplSttExceptList();
1949 if(bAbbreviation ? lcl_FindAbbreviation( pList, sWord)
1950 : pList->Seek_Entry( &sTemp ) )
1951 return TRUE;
1953 // wenn es hier noch nicht gefunden werden konnte, dann weitersuchen
1954 ULONG nTmp;
1956 if( ((nTmp = nTmpKey1) != (ULONG)eLang &&
1957 ( pLangTable->IsKeyValid( nTmpKey1 ) ||
1958 CreateLanguageFile( LanguageType( nTmpKey1 ), FALSE ) )) ||
1959 (( nTmp = nTmpKey2) != (ULONG)eLang &&
1960 ( pLangTable->IsKeyValid( nTmpKey2 ) ||
1961 CreateLanguageFile( LanguageType( nTmpKey2 ), FALSE ) )) )
1963 //die Sprache ist vorhanden - also her damit
1964 SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(nTmp);
1965 const SvStringsISortDtor* pList = pLists->GetCplSttExceptList();
1966 if(bAbbreviation ? lcl_FindAbbreviation( pList, sWord)
1967 : pList->Seek_Entry( &sTemp ) )
1968 return TRUE;
1970 if(pLangTable->IsKeyValid(ULONG(LANGUAGE_DONTKNOW))|| CreateLanguageFile(LANGUAGE_DONTKNOW, FALSE))
1972 //die Sprache ist vorhanden - also her damit
1973 SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(LANGUAGE_DONTKNOW);
1974 const SvStringsISortDtor* pList = pLists->GetCplSttExceptList();
1975 if(bAbbreviation ? lcl_FindAbbreviation( pList, sWord)
1976 : pList->Seek_Entry( &sTemp ) )
1977 return TRUE;
1979 return FALSE;
1983 /* -----------------20.11.98 11:53-------------------
1985 * --------------------------------------------------*/
1986 String SvxAutoCorrect::GetAutoCorrFileName( LanguageType eLang,
1987 BOOL bNewFile, BOOL bTst ) const
1989 String sRet, sExt( MsLangId::convertLanguageToIsoString( eLang ) );
1990 sExt.Insert('_', 0);
1991 sExt.AppendAscii( ".dat" );
1992 if( bNewFile )
1993 ( sRet = sUserAutoCorrFile ) += sExt;
1994 else if( !bTst )
1995 ( sRet = sShareAutoCorrFile ) += sExt;
1996 else
1998 // test first in the user directory - if not exist, then
1999 ( sRet = sUserAutoCorrFile ) += sExt;
2000 if( !FStatHelper::IsDocument( sRet ))
2001 ( sRet = sShareAutoCorrFile ) += sExt;
2003 return sRet;
2006 /* -----------------18.11.98 11:16-------------------
2008 * --------------------------------------------------*/
2009 SvxAutoCorrectLanguageLists::SvxAutoCorrectLanguageLists(
2010 SvxAutoCorrect& rParent,
2011 const String& rShareAutoCorrectFile,
2012 const String& rUserAutoCorrectFile,
2013 LanguageType eLang)
2014 : sShareAutoCorrFile( rShareAutoCorrectFile ),
2015 sUserAutoCorrFile( rUserAutoCorrectFile ),
2016 eLanguage(eLang),
2017 pCplStt_ExcptLst( 0 ),
2018 pWrdStt_ExcptLst( 0 ),
2019 pAutocorr_List( 0 ),
2020 rAutoCorrect(rParent),
2021 nFlags(0)
2025 /* -----------------18.11.98 11:16-------------------
2027 * --------------------------------------------------*/
2028 SvxAutoCorrectLanguageLists::~SvxAutoCorrectLanguageLists()
2030 delete pCplStt_ExcptLst;
2031 delete pWrdStt_ExcptLst;
2032 delete pAutocorr_List;
2035 /* -----------------18.11.98 11:26-------------------
2037 * --------------------------------------------------*/
2038 BOOL SvxAutoCorrectLanguageLists::IsFileChanged_Imp()
2040 // nur alle 2 Minuten aufs FileSystem zugreifen um den
2041 // Dateistempel zu ueberpruefen
2042 BOOL bRet = FALSE;
2044 Time nMinTime( 0, 2 );
2045 Time nAktTime;
2046 if( aLastCheckTime > nAktTime || // ueberlauf ?
2047 ( nAktTime -= aLastCheckTime ) > nMinTime ) // min Zeit vergangen
2049 Date aTstDate; Time aTstTime;
2050 if( FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile,
2051 &aTstDate, &aTstTime ) &&
2052 ( aModifiedDate != aTstDate || aModifiedTime != aTstTime ))
2054 bRet = TRUE;
2055 // dann mal schnell alle Listen entfernen!
2056 if( CplSttLstLoad & nFlags && pCplStt_ExcptLst )
2057 delete pCplStt_ExcptLst, pCplStt_ExcptLst = 0;
2058 if( WrdSttLstLoad & nFlags && pWrdStt_ExcptLst )
2059 delete pWrdStt_ExcptLst, pWrdStt_ExcptLst = 0;
2060 if( ChgWordLstLoad & nFlags && pAutocorr_List )
2061 delete pAutocorr_List, pAutocorr_List = 0;
2062 nFlags &= ~(CplSttLstLoad | WrdSttLstLoad | ChgWordLstLoad );
2064 aLastCheckTime = Time();
2066 return bRet;
2069 void SvxAutoCorrectLanguageLists::LoadXMLExceptList_Imp(
2070 SvStringsISortDtor*& rpLst,
2071 const sal_Char* pStrmName,
2072 SotStorageRef& rStg)
2074 if( rpLst )
2075 rpLst->DeleteAndDestroy( 0, rpLst->Count() );
2076 else
2077 rpLst = new SvStringsISortDtor( 16, 16 );
2080 String sStrmName( pStrmName, RTL_TEXTENCODING_MS_1252 );
2081 String sTmp( sStrmName );
2083 if( rStg.Is() && rStg->IsStream( sStrmName ) )
2085 SvStorageStreamRef xStrm = rStg->OpenSotStream( sTmp,
2086 ( STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE ) );
2087 if( SVSTREAM_OK != xStrm->GetError())
2089 xStrm.Clear();
2090 rStg.Clear();
2091 RemoveStream_Imp( sStrmName );
2093 else
2095 uno::Reference< lang::XMultiServiceFactory > xServiceFactory =
2096 comphelper::getProcessServiceFactory();
2097 DBG_ASSERT( xServiceFactory.is(),
2098 "XMLReader::Read: got no service manager" );
2099 if( !xServiceFactory.is() )
2101 // Throw an exception ?
2104 xml::sax::InputSource aParserInput;
2105 aParserInput.sSystemId = sStrmName;
2107 xStrm->Seek( 0L );
2108 xStrm->SetBufferSize( 8 * 1024 );
2109 aParserInput.aInputStream = new utl::OInputStreamWrapper( *xStrm );
2111 // get parser
2112 uno::Reference< XInterface > xXMLParser = xServiceFactory->createInstance(
2113 OUString::createFromAscii("com.sun.star.xml.sax.Parser") );
2114 DBG_ASSERT( xXMLParser.is(),
2115 "XMLReader::Read: com.sun.star.xml.sax.Parser service missing" );
2116 if( !xXMLParser.is() )
2118 // Maybe throw an exception?
2121 // get filter
2122 // #110680#
2123 // uno::Reference< xml::sax::XDocumentHandler > xFilter = new SvXMLExceptionListImport ( *rpLst );
2124 uno::Reference< xml::sax::XDocumentHandler > xFilter = new SvXMLExceptionListImport ( xServiceFactory, *rpLst );
2126 // connect parser and filter
2127 uno::Reference< xml::sax::XParser > xParser( xXMLParser, UNO_QUERY );
2128 xParser->setDocumentHandler( xFilter );
2130 // parse
2133 xParser->parseStream( aParserInput );
2135 catch( xml::sax::SAXParseException& )
2137 // re throw ?
2139 catch( xml::sax::SAXException& )
2141 // re throw ?
2143 catch( io::IOException& )
2145 // re throw ?
2150 // Zeitstempel noch setzen
2151 FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile,
2152 &aModifiedDate, &aModifiedTime );
2153 aLastCheckTime = Time();
2157 /* -----------------18.11.98 11:26-------------------
2159 * --------------------------------------------------*/
2160 void SvxAutoCorrectLanguageLists::SaveExceptList_Imp(
2161 const SvStringsISortDtor& rLst,
2162 const sal_Char* pStrmName,
2163 SotStorageRef &rStg,
2164 BOOL bConvert )
2166 if( rStg.Is() )
2168 String sStrmName( pStrmName, RTL_TEXTENCODING_MS_1252 );
2169 if( !rLst.Count() )
2171 rStg->Remove( sStrmName );
2172 rStg->Commit();
2174 else
2176 SotStorageStreamRef xStrm = rStg->OpenSotStream( sStrmName,
2177 ( STREAM_READ | STREAM_WRITE | STREAM_SHARE_DENYWRITE ) );
2178 if( xStrm.Is() )
2180 xStrm->SetSize( 0 );
2181 xStrm->SetBufferSize( 8192 );
2182 String aPropName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("MediaType") ) );
2183 OUString aMime( RTL_CONSTASCII_USTRINGPARAM("text/xml") );
2184 uno::Any aAny;
2185 aAny <<= aMime;
2186 xStrm->SetProperty( aPropName, aAny );
2189 uno::Reference< lang::XMultiServiceFactory > xServiceFactory =
2190 comphelper::getProcessServiceFactory();
2191 DBG_ASSERT( xServiceFactory.is(),
2192 "XMLReader::Read: got no service manager" );
2193 if( !xServiceFactory.is() )
2195 // Throw an exception ?
2198 uno::Reference < XInterface > xWriter (xServiceFactory->createInstance(
2199 OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.sax.Writer"))));
2200 DBG_ASSERT(xWriter.is(),"com.sun.star.xml.sax.Writer service missing");
2201 uno::Reference < io::XOutputStream> xOut = new utl::OOutputStreamWrapper( *xStrm );
2202 uno::Reference<io::XActiveDataSource> xSrc(xWriter, uno::UNO_QUERY);
2203 xSrc->setOutputStream(xOut);
2205 uno::Reference<xml::sax::XDocumentHandler> xHandler(xWriter, uno::UNO_QUERY);
2207 // #110680#
2208 // SvXMLExceptionListExport aExp(rLst, sStrmName, xHandler);
2209 SvXMLExceptionListExport aExp( xServiceFactory, rLst, sStrmName, xHandler );
2211 aExp.exportDoc( XML_BLOCK_LIST );
2213 xStrm->Commit();
2214 if( xStrm->GetError() == SVSTREAM_OK )
2216 xStrm.Clear();
2217 if (!bConvert)
2219 rStg->Commit();
2220 if( SVSTREAM_OK != rStg->GetError() )
2222 rStg->Remove( sStrmName );
2223 rStg->Commit();
2231 /* -----------------18.11.98 11:26-------------------
2233 * --------------------------------------------------*/
2234 SvxAutocorrWordList* SvxAutoCorrectLanguageLists::LoadAutocorrWordList()
2236 if( pAutocorr_List )
2237 pAutocorr_List->DeleteAndDestroy( 0, pAutocorr_List->Count() );
2238 else
2239 pAutocorr_List = new SvxAutocorrWordList( 16, 16 );
2241 SvStringsDtor aRemoveArr;
2244 uno::Reference < embed::XStorage > xStg = comphelper::OStorageHelper::GetStorageFromURL( sShareAutoCorrFile, embed::ElementModes::READ );
2245 String aXMLWordListName( pXMLImplAutocorr_ListStr, RTL_TEXTENCODING_MS_1252 );
2246 uno::Reference < io::XStream > xStrm = xStg->openStreamElement( aXMLWordListName, embed::ElementModes::READ );
2247 uno::Reference< lang::XMultiServiceFactory > xServiceFactory = comphelper::getProcessServiceFactory();
2249 xml::sax::InputSource aParserInput;
2250 aParserInput.sSystemId = aXMLWordListName;
2251 aParserInput.aInputStream = xStrm->getInputStream();
2253 // get parser
2254 uno::Reference< XInterface > xXMLParser = xServiceFactory->createInstance( OUString::createFromAscii("com.sun.star.xml.sax.Parser") );
2255 DBG_ASSERT( xXMLParser.is(), "XMLReader::Read: com.sun.star.xml.sax.Parser service missing" );
2256 if( xXMLParser.is() )
2258 uno::Reference< xml::sax::XDocumentHandler > xFilter = new SvXMLAutoCorrectImport( xServiceFactory, pAutocorr_List, rAutoCorrect, xStg );
2260 // connect parser and filter
2261 uno::Reference< xml::sax::XParser > xParser( xXMLParser, UNO_QUERY );
2262 xParser->setDocumentHandler( xFilter );
2264 // parse
2265 xParser->parseStream( aParserInput );
2268 catch ( uno::Exception& )
2272 // Zeitstempel noch setzen
2273 FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile,
2274 &aModifiedDate, &aModifiedTime );
2275 aLastCheckTime = Time();
2277 return pAutocorr_List;
2280 /* -----------------18.11.98 11:26-------------------
2282 * --------------------------------------------------*/
2284 void SvxAutoCorrectLanguageLists::SetAutocorrWordList( SvxAutocorrWordList* pList )
2286 if( pAutocorr_List && pList != pAutocorr_List )
2287 delete pAutocorr_List;
2288 pAutocorr_List = pList;
2289 if( !pAutocorr_List )
2291 DBG_ASSERT( !this, "keine gueltige Liste" );
2292 pAutocorr_List = new SvxAutocorrWordList( 16, 16 );
2294 nFlags |= ChgWordLstLoad;
2297 /* -----------------18.11.98 11:26-------------------
2299 * --------------------------------------------------*/
2300 const SvxAutocorrWordList* SvxAutoCorrectLanguageLists::GetAutocorrWordList()
2302 if( !( ChgWordLstLoad & nFlags ) || IsFileChanged_Imp() )
2303 SetAutocorrWordList( LoadAutocorrWordList() );
2304 return pAutocorr_List;
2306 /* -----------------18.11.98 11:26-------------------
2308 * --------------------------------------------------*/
2309 SvStringsISortDtor* SvxAutoCorrectLanguageLists::GetCplSttExceptList()
2311 if( !( CplSttLstLoad & nFlags ) || IsFileChanged_Imp() )
2312 SetCplSttExceptList( LoadCplSttExceptList() );
2313 return pCplStt_ExcptLst;
2315 /* -----------------18.11.98 11:26-------------------
2317 * --------------------------------------------------*/
2318 BOOL SvxAutoCorrectLanguageLists::AddToCplSttExceptList(const String& rNew)
2320 String* pNew = new String( rNew );
2321 if( rNew.Len() && GetCplSttExceptList()->Insert( pNew ) )
2323 MakeUserStorage_Impl();
2324 SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE );
2326 SaveExceptList_Imp( *pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg );
2328 xStg = 0;
2329 // Zeitstempel noch setzen
2330 FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
2331 &aModifiedDate, &aModifiedTime );
2332 aLastCheckTime = Time();
2334 else
2335 delete pNew, pNew = 0;
2336 return 0 != pNew;
2338 /* -----------------18.11.98 15:20-------------------
2340 * --------------------------------------------------*/
2341 BOOL SvxAutoCorrectLanguageLists::AddToWrdSttExceptList(const String& rNew)
2343 String* pNew = new String( rNew );
2344 SvStringsISortDtor* pExceptList = LoadWrdSttExceptList();
2345 if( rNew.Len() && pExceptList && pExceptList->Insert( pNew ) )
2347 MakeUserStorage_Impl();
2348 SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE );
2350 SaveExceptList_Imp( *pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg );
2352 xStg = 0;
2353 // Zeitstempel noch setzen
2354 FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
2355 &aModifiedDate, &aModifiedTime );
2356 aLastCheckTime = Time();
2358 else
2359 delete pNew, pNew = 0;
2360 return 0 != pNew;
2363 /* -----------------18.11.98 11:26-------------------
2365 * --------------------------------------------------*/
2366 SvStringsISortDtor* SvxAutoCorrectLanguageLists::LoadCplSttExceptList()
2368 SotStorageRef xStg = new SotStorage( sShareAutoCorrFile, STREAM_READ | STREAM_SHARE_DENYNONE, TRUE );
2369 String sTemp ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplCplStt_ExcptLstStr ) );
2370 if( xStg.Is() && xStg->IsContained( sTemp ) )
2371 LoadXMLExceptList_Imp( pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg );
2373 return pCplStt_ExcptLst;
2376 /* -----------------18.11.98 11:26-------------------
2378 * --------------------------------------------------*/
2379 void SvxAutoCorrectLanguageLists::SaveCplSttExceptList()
2381 MakeUserStorage_Impl();
2382 SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE );
2384 SaveExceptList_Imp( *pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg );
2386 xStg = 0;
2388 // Zeitstempel noch setzen
2389 FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
2390 &aModifiedDate, &aModifiedTime );
2391 aLastCheckTime = Time();
2394 /* -----------------18.11.98 11:26-------------------
2396 * --------------------------------------------------*/
2397 void SvxAutoCorrectLanguageLists::SetCplSttExceptList( SvStringsISortDtor* pList )
2399 if( pCplStt_ExcptLst && pList != pCplStt_ExcptLst )
2400 delete pCplStt_ExcptLst;
2402 pCplStt_ExcptLst = pList;
2403 if( !pCplStt_ExcptLst )
2405 DBG_ASSERT( !this, "keine gueltige Liste" );
2406 pCplStt_ExcptLst = new SvStringsISortDtor( 16, 16 );
2408 nFlags |= CplSttLstLoad;
2410 /* -----------------18.11.98 11:26-------------------
2412 * --------------------------------------------------*/
2413 SvStringsISortDtor* SvxAutoCorrectLanguageLists::LoadWrdSttExceptList()
2415 SotStorageRef xStg = new SotStorage( sShareAutoCorrFile, STREAM_READ | STREAM_SHARE_DENYNONE, TRUE );
2416 String sTemp ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplWrdStt_ExcptLstStr ) );
2417 if( xStg.Is() && xStg->IsContained( sTemp ) )
2418 LoadXMLExceptList_Imp( pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg );
2419 return pWrdStt_ExcptLst;
2421 /* -----------------18.11.98 11:26-------------------
2423 * --------------------------------------------------*/
2424 void SvxAutoCorrectLanguageLists::SaveWrdSttExceptList()
2426 MakeUserStorage_Impl();
2427 SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE );
2429 SaveExceptList_Imp( *pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg );
2431 xStg = 0;
2432 // Zeitstempel noch setzen
2433 FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile,
2434 &aModifiedDate, &aModifiedTime );
2435 aLastCheckTime = Time();
2437 /* -----------------18.11.98 11:26-------------------
2439 * --------------------------------------------------*/
2440 void SvxAutoCorrectLanguageLists::SetWrdSttExceptList( SvStringsISortDtor* pList )
2442 if( pWrdStt_ExcptLst && pList != pWrdStt_ExcptLst )
2443 delete pWrdStt_ExcptLst;
2444 pWrdStt_ExcptLst = pList;
2445 if( !pWrdStt_ExcptLst )
2447 DBG_ASSERT( !this, "keine gueltige Liste" );
2448 pWrdStt_ExcptLst = new SvStringsISortDtor( 16, 16 );
2450 nFlags |= WrdSttLstLoad;
2452 /* -----------------18.11.98 11:26-------------------
2454 * --------------------------------------------------*/
2455 SvStringsISortDtor* SvxAutoCorrectLanguageLists::GetWrdSttExceptList()
2457 if( !( WrdSttLstLoad & nFlags ) || IsFileChanged_Imp() )
2458 SetWrdSttExceptList( LoadWrdSttExceptList() );
2459 return pWrdStt_ExcptLst;
2461 /* -----------------18.11.98 11:26-------------------
2463 * --------------------------------------------------*/
2464 void SvxAutoCorrectLanguageLists::RemoveStream_Imp( const String& rName )
2466 if( sShareAutoCorrFile != sUserAutoCorrFile )
2468 SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE );
2469 if( xStg.Is() && SVSTREAM_OK == xStg->GetError() &&
2470 xStg->IsStream( rName ) )
2472 xStg->Remove( rName );
2473 xStg->Commit();
2475 xStg = 0;
2480 void SvxAutoCorrectLanguageLists::MakeUserStorage_Impl()
2482 // The conversion needs to happen if the file is already in the user
2483 // directory and is in the old format. Additionally it needs to
2484 // happen when the file is being copied from share to user.
2486 sal_Bool bError = sal_False, bConvert = sal_False, bCopy = sal_False;
2487 INetURLObject aDest;
2488 INetURLObject aSource;
2490 // String sDestPath = sUserAutoCorrFile.Copy ( 0, sUserAutoCorrFile.Len()-3);
2491 // sDestPath.AppendAscii ("bak");
2494 if (sUserAutoCorrFile != sShareAutoCorrFile )
2496 aSource = INetURLObject ( sShareAutoCorrFile ); //aSource.setFSysPath ( sShareAutoCorrFile, INetURLObject::FSYS_DETECT );
2497 aDest = INetURLObject ( sUserAutoCorrFile );
2498 if ( SotStorage::IsOLEStorage ( sShareAutoCorrFile ) )
2500 aDest.SetExtension ( String::CreateFromAscii ( "bak" ) );
2501 bConvert = sal_True;
2503 bCopy = sal_True;
2505 else if ( SotStorage::IsOLEStorage ( sUserAutoCorrFile ) )
2507 aSource = INetURLObject ( sUserAutoCorrFile );
2508 aDest = INetURLObject ( sUserAutoCorrFile );
2509 aDest.SetExtension ( String::CreateFromAscii ( "bak" ) );
2510 bCopy = bConvert = sal_True;
2512 if (bCopy)
2516 String sMain(aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ));
2517 sal_Unicode cSlash = '/';
2518 xub_StrLen nSlashPos = sMain.SearchBackward(cSlash);
2519 sMain.Erase(nSlashPos);
2520 ::ucbhelper::Content aNewContent( sMain, uno::Reference< XCommandEnvironment > ());
2521 Any aAny;
2522 TransferInfo aInfo;
2523 aInfo.NameClash = NameClash::OVERWRITE;
2524 aInfo.NewTitle = aDest.GetName();
2525 aInfo.SourceURL = aSource.GetMainURL( INetURLObject::DECODE_TO_IURI );
2526 aInfo.MoveData = FALSE;
2527 aAny <<= aInfo;
2528 aNewContent.executeCommand( OUString ( RTL_CONSTASCII_USTRINGPARAM( "transfer" ) ), aAny);
2530 catch (...)
2532 bError = sal_True;
2535 if (bConvert && !bError)
2537 SotStorageRef xSrcStg = new SotStorage( aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ), STREAM_READ, TRUE );
2538 SotStorageRef xDstStg = new SotStorage( sUserAutoCorrFile, STREAM_WRITE, TRUE );
2540 if( xSrcStg.Is() && xDstStg.Is() )
2542 String sWord ( RTL_CONSTASCII_USTRINGPARAM ( pImplWrdStt_ExcptLstStr ) );
2543 String sSentence ( RTL_CONSTASCII_USTRINGPARAM ( pImplCplStt_ExcptLstStr ) );
2544 String sXMLWord ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplWrdStt_ExcptLstStr ) );
2545 String sXMLSentence ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplCplStt_ExcptLstStr ) );
2546 SvStringsISortDtor *pTmpWordList = NULL;
2548 if (xSrcStg->IsContained( sXMLWord ) )
2549 LoadXMLExceptList_Imp( pTmpWordList, pXMLImplWrdStt_ExcptLstStr, xSrcStg );
2551 if (pTmpWordList)
2553 SaveExceptList_Imp( *pTmpWordList, pXMLImplWrdStt_ExcptLstStr, xDstStg, TRUE );
2554 pTmpWordList->DeleteAndDestroy( 0, pTmpWordList->Count() );
2555 pTmpWordList = NULL;
2559 if (xSrcStg->IsContained( sXMLSentence ) )
2560 LoadXMLExceptList_Imp( pTmpWordList, pXMLImplCplStt_ExcptLstStr, xSrcStg );
2562 if (pTmpWordList)
2564 SaveExceptList_Imp( *pTmpWordList, pXMLImplCplStt_ExcptLstStr, xDstStg, TRUE );
2565 pTmpWordList->DeleteAndDestroy( 0, pTmpWordList->Count() );
2568 GetAutocorrWordList();
2569 MakeBlocklist_Imp( *xDstStg );
2570 // xDstStg is committed in MakeBlocklist_Imp
2571 /*xSrcStg->CopyTo( &xDstStg );*/
2572 sShareAutoCorrFile = sUserAutoCorrFile;
2573 xDstStg = 0;
2576 ::ucbhelper::Content aContent ( aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ), uno::Reference < XCommandEnvironment > ());
2577 aContent.executeCommand ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "delete" ) ), makeAny ( sal_Bool (sal_True ) ) );
2579 catch (...)
2584 else if( bCopy && !bError )
2585 sShareAutoCorrFile = sUserAutoCorrFile;
2588 /* -----------------18.11.98 11:26-------------------
2590 * --------------------------------------------------*/
2591 BOOL SvxAutoCorrectLanguageLists::MakeBlocklist_Imp( SvStorage& rStg )
2593 String sStrmName( pXMLImplAutocorr_ListStr, RTL_TEXTENCODING_MS_1252 );
2594 BOOL bRet = TRUE, bRemove = !pAutocorr_List || !pAutocorr_List->Count();
2595 if( !bRemove )
2598 if ( rStg.IsContained( sStrmName) )
2600 rStg.Remove ( sStrmName );
2601 rStg.Commit();
2604 SvStorageStreamRef refList = rStg.OpenSotStream( sStrmName,
2605 ( STREAM_READ | STREAM_WRITE | STREAM_SHARE_DENYWRITE ) );
2606 if( refList.Is() )
2608 refList->SetSize( 0 );
2609 refList->SetBufferSize( 8192 );
2610 String aPropName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("MediaType") ) );
2611 OUString aMime( RTL_CONSTASCII_USTRINGPARAM("text/xml") );
2612 uno::Any aAny;
2613 aAny <<= aMime;
2614 refList->SetProperty( aPropName, aAny );
2616 uno::Reference< lang::XMultiServiceFactory > xServiceFactory =
2617 comphelper::getProcessServiceFactory();
2618 DBG_ASSERT( xServiceFactory.is(),
2619 "XMLReader::Read: got no service manager" );
2620 if( !xServiceFactory.is() )
2622 // Throw an exception ?
2625 uno::Reference < XInterface > xWriter (xServiceFactory->createInstance(
2626 OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.sax.Writer"))));
2627 DBG_ASSERT(xWriter.is(),"com.sun.star.xml.sax.Writer service missing");
2628 uno::Reference < io::XOutputStream> xOut = new utl::OOutputStreamWrapper( *refList );
2629 uno::Reference<io::XActiveDataSource> xSrc(xWriter, uno::UNO_QUERY);
2630 xSrc->setOutputStream(xOut);
2632 uno::Reference<xml::sax::XDocumentHandler> xHandler(xWriter, uno::UNO_QUERY);
2634 // #110680#
2635 // SvXMLAutoCorrectExport aExp(pAutocorr_List, sStrmName, xHandler);
2636 SvXMLAutoCorrectExport aExp( xServiceFactory, pAutocorr_List, sStrmName, xHandler );
2638 aExp.exportDoc( XML_BLOCK_LIST );
2640 refList->Commit();
2641 bRet = SVSTREAM_OK == refList->GetError();
2642 if( bRet )
2644 refList.Clear();
2645 rStg.Commit();
2646 if( SVSTREAM_OK != rStg.GetError() )
2648 bRemove = TRUE;
2649 bRet = FALSE;
2654 refList->SetSize( 0 );
2655 refList->SetBufferSize( 8192 );
2656 rtl_TextEncoding eEncoding = gsl_getSystemTextEncoding();
2658 String aDummy; // Erkennungszeichen fuer neue Streams
2659 refList->WriteByteString( aDummy, RTL_TEXTENCODING_MS_1252 )
2660 << (BYTE) 4 // Laenge des Headers (ohne den Leerstring)
2661 << (USHORT)WORDLIST_VERSION_358 // Version des Streams
2662 << (BYTE)eEncoding; // der Zeichensatz
2664 for( USHORT i = 0; i < pAutocorr_List->Count() &&
2665 SVSTREAM_OK == refList->GetError(); ++i )
2667 SvxAutocorrWord* p = pAutocorr_List->GetObject( i );
2668 refList->WriteByteString( p->GetShort(), eEncoding ).
2669 WriteByteString( p->IsTextOnly()
2670 ? p->GetLong()
2671 : p->GetShort(), eEncoding );
2673 refList->Commit();
2674 bRet = SVSTREAM_OK == refList->GetError();
2675 if( bRet )
2677 refList.Clear();
2678 rStg.Commit();
2679 if( SVSTREAM_OK != rStg.GetError() )
2681 bRemove = TRUE;
2682 bRet = FALSE;
2687 else
2688 bRet = FALSE;
2691 if( bRemove )
2693 rStg.Remove( sStrmName );
2694 rStg.Commit();
2697 return bRet;
2700 /* -----------------18.11.98 11:26-------------------
2702 * --------------------------------------------------*/
2703 BOOL SvxAutoCorrectLanguageLists::PutText( const String& rShort,
2704 const String& rLong )
2706 // erstmal akt. Liste besorgen!
2707 GetAutocorrWordList();
2709 MakeUserStorage_Impl();
2710 SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE );
2712 BOOL bRet = xStg.Is() && SVSTREAM_OK == xStg->GetError();
2714 /* if( bRet )
2716 // PutText( *xStg, rShort );
2719 // die Wortliste aktualisieren
2720 if( bRet )
2722 USHORT nPos;
2723 SvxAutocorrWord* pNew = new SvxAutocorrWord( rShort, rLong, TRUE );
2724 if( pAutocorr_List->Seek_Entry( pNew, &nPos ) )
2726 if( !(*pAutocorr_List)[ nPos ]->IsTextOnly() )
2728 // dann ist der Storage noch zu entfernen
2729 String sStgNm( rShort );
2730 if (xStg->IsOLEStorage())
2731 EncryptBlockName_Imp( sStgNm );
2732 else
2733 GeneratePackageName ( rShort, sStgNm);
2735 if( xStg->IsContained( sStgNm ) )
2736 xStg->Remove( sStgNm );
2738 pAutocorr_List->DeleteAndDestroy( nPos );
2741 if( pAutocorr_List->Insert( pNew ) )
2743 bRet = MakeBlocklist_Imp( *xStg );
2744 xStg = 0;
2746 else
2748 delete pNew;
2749 bRet = FALSE;
2752 return bRet;
2754 /* -----------------18.11.98 11:26-------------------
2756 * --------------------------------------------------*/
2757 // - Text mit Attributierung (kann nur der SWG - SWG-Format!)
2758 BOOL SvxAutoCorrectLanguageLists::PutText( const String& rShort,
2759 SfxObjectShell& rShell )
2761 // erstmal akt. Liste besorgen!
2762 GetAutocorrWordList();
2764 MakeUserStorage_Impl();
2766 BOOL bRet = FALSE;
2767 String sLong;
2770 uno::Reference < embed::XStorage > xStg = comphelper::OStorageHelper::GetStorageFromURL( sUserAutoCorrFile, embed::ElementModes::READWRITE );
2771 // String aName( rShort );
2772 // EncryptBlockName_Imp( aName );
2773 // bRet = PutText( *xStg, aName, rShell, sLong );
2774 bRet = rAutoCorrect.PutText( xStg, sUserAutoCorrFile, rShort, rShell, sLong );
2775 xStg = 0;
2777 // die Wortliste aktualisieren
2778 if( bRet )
2780 SvxAutocorrWord* pNew = new SvxAutocorrWord( rShort, sLong, FALSE );
2781 if( pAutocorr_List->Insert( pNew ) )
2783 SotStorageRef xStor = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE );
2784 MakeBlocklist_Imp( *xStor );
2786 else
2787 delete pNew;
2790 catch ( uno::Exception& )
2794 return bRet;
2797 /* -----------------18.11.98 11:26-------------------
2799 * --------------------------------------------------*/
2800 // - loesche einen Eintrag
2801 BOOL SvxAutoCorrectLanguageLists::DeleteText( const String& rShort )
2803 // erstmal akt. Liste besorgen!
2804 GetAutocorrWordList();
2806 MakeUserStorage_Impl();
2808 SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE );
2809 BOOL bRet = xStg.Is() && SVSTREAM_OK == xStg->GetError();
2810 if( bRet )
2812 USHORT nPos;
2813 SvxAutocorrWord aTmp( rShort, rShort );
2814 if( pAutocorr_List->Seek_Entry( &aTmp, &nPos ) )
2816 SvxAutocorrWord* pFnd = (*pAutocorr_List)[ nPos ];
2817 if( !pFnd->IsTextOnly() )
2819 String aName( rShort );
2820 if (xStg->IsOLEStorage())
2821 EncryptBlockName_Imp( aName );
2822 else
2823 GeneratePackageName ( rShort, aName );
2824 if( xStg->IsContained( aName ) )
2826 xStg->Remove( aName );
2827 bRet = xStg->Commit();
2831 // die Wortliste aktualisieren
2832 pAutocorr_List->DeleteAndDestroy( nPos );
2833 MakeBlocklist_Imp( *xStg );
2834 xStg = 0;
2836 else
2837 bRet = FALSE;
2839 return bRet;