1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_editeng.hxx" 30 31 #include <vcl/wrkwin.hxx> 32 #include <vcl/dialog.hxx> 33 #include <vcl/msgbox.hxx> 34 #include <vcl/svapp.hxx> 35 36 #include <svl/srchitem.hxx> 37 #include <editeng/lspcitem.hxx> 38 #include <editeng/adjitem.hxx> 39 #include <editeng/tstpitem.hxx> 40 41 #include <eertfpar.hxx> 42 #include <editeng/editeng.hxx> 43 #include <impedit.hxx> 44 #include <editeng/editview.hxx> 45 #include <eehtml.hxx> 46 #include <editobj2.hxx> 47 #include <i18npool/lang.h> 48 49 #include "editxml.hxx" 50 51 #include <editeng/akrnitem.hxx> 52 #include <editeng/cntritem.hxx> 53 #include <editeng/colritem.hxx> 54 #include <editeng/crsditem.hxx> 55 #include <editeng/escpitem.hxx> 56 #include <editeng/fhgtitem.hxx> 57 #include <editeng/fontitem.hxx> 58 #include <editeng/kernitem.hxx> 59 #include <editeng/lrspitem.hxx> 60 #include <editeng/postitem.hxx> 61 #include <editeng/shdditem.hxx> 62 #include <editeng/udlnitem.hxx> 63 #include <editeng/ulspitem.hxx> 64 #include <editeng/wghtitem.hxx> 65 #include <editeng/langitem.hxx> 66 #include <editeng/charreliefitem.hxx> 67 #include <editeng/frmdiritem.hxx> 68 #include <editeng/emphitem.hxx> 69 #include <textconv.hxx> 70 #include <rtl/tencinfo.h> 71 #include <svtools/rtfout.hxx> 72 #include <edtspell.hxx> 73 #include <editeng/scripttypeitem.hxx> 74 #include <editeng/unolingu.hxx> 75 #include <linguistic/lngprops.hxx> 76 #include <com/sun/star/linguistic2/XThesaurus.hpp> 77 #include <com/sun/star/linguistic2/XMeaning.hpp> 78 #include <com/sun/star/i18n/ScriptType.hpp> 79 #include <com/sun/star/i18n/WordType.hpp> 80 #include <com/sun/star/i18n/TransliterationModules.hpp> 81 #include <com/sun/star/i18n/TransliterationModulesExtra.hpp> 82 #include <unotools/transliterationwrapper.hxx> 83 #include <unotools/textsearch.hxx> 84 #include <comphelper/processfactory.hxx> 85 #include <vcl/help.hxx> 86 #include <svtools/rtfkeywd.hxx> 87 #include <editeng/edtdlg.hxx> 88 89 #include <vector> 90 91 using namespace ::com::sun::star; 92 using namespace ::com::sun::star::uno; 93 using namespace ::com::sun::star::beans; 94 using namespace ::com::sun::star::linguistic2; 95 96 void Swapsal_uIt16s( sal_uInt16& rX, sal_uInt16& rY ) 97 { 98 sal_uInt16 n = rX; 99 rX = rY; 100 rY = n; 101 } 102 103 EditPaM ImpEditEngine::Read( SvStream& rInput, const String& rBaseURL, EETextFormat eFormat, EditSelection aSel, SvKeyValueIterator* pHTTPHeaderAttrs ) 104 { 105 sal_Bool _bUpdate = GetUpdateMode(); 106 SetUpdateMode( sal_False ); 107 EditPaM aPaM; 108 if ( eFormat == EE_FORMAT_TEXT ) 109 aPaM = ReadText( rInput, aSel ); 110 else if ( eFormat == EE_FORMAT_RTF ) 111 aPaM = ReadRTF( rInput, aSel ); 112 else if ( eFormat == EE_FORMAT_XML ) 113 aPaM = ReadXML( rInput, aSel ); 114 else if ( eFormat == EE_FORMAT_HTML ) 115 aPaM = ReadHTML( rInput, rBaseURL, aSel, pHTTPHeaderAttrs ); 116 else if ( eFormat == EE_FORMAT_BIN) 117 aPaM = ReadBin( rInput, aSel ); 118 else 119 { 120 DBG_ERROR( "Read: Unbekanntes Format" ); 121 } 122 123 FormatFullDoc(); // reicht vielleicht auch ein einfaches Format? 124 SetUpdateMode( _bUpdate ); 125 126 return aPaM; 127 } 128 129 EditPaM ImpEditEngine::ReadText( SvStream& rInput, EditSelection aSel ) 130 { 131 if ( aSel.HasRange() ) 132 aSel = ImpDeleteSelection( aSel ); 133 EditPaM aPaM = aSel.Max(); 134 135 XubString aTmpStr, aStr; 136 sal_Bool bDone = rInput.ReadByteStringLine( aTmpStr ); 137 while ( bDone ) 138 { 139 aTmpStr.Erase( MAXCHARSINPARA ); 140 aPaM = ImpInsertText( EditSelection( aPaM, aPaM ), aTmpStr ); 141 aPaM = ImpInsertParaBreak( aPaM ); 142 bDone = rInput.ReadByteStringLine( aTmpStr ); 143 } 144 return aPaM; 145 } 146 147 EditPaM ImpEditEngine::ReadXML( SvStream& rInput, EditSelection aSel ) 148 { 149 #ifndef SVX_LIGHT 150 if ( aSel.HasRange() ) 151 aSel = ImpDeleteSelection( aSel ); 152 153 ESelection aESel = CreateESel( aSel ); 154 155 ::SvxReadXML( *GetEditEnginePtr(), rInput, aESel ); 156 157 return aSel.Max(); 158 #else 159 return EditPaM(); 160 #endif 161 } 162 163 EditPaM ImpEditEngine::ReadRTF( SvStream& rInput, EditSelection aSel ) 164 { 165 #ifndef SVX_LIGHT 166 167 #if defined (EDITDEBUG) && !defined( UNX ) 168 SvFileStream aRTFOut( String( RTL_CONSTASCII_USTRINGPARAM ( "d:\\rtf_in.rtf" ) ), STREAM_WRITE ); 169 aRTFOut << rInput; 170 aRTFOut.Close(); 171 rInput.Seek( 0 ); 172 #endif 173 if ( aSel.HasRange() ) 174 aSel = ImpDeleteSelection( aSel ); 175 176 // sal_Bool bCharsBeforeInsertPos = ( aSel.Min().GetIndex() ) ? sal_True : sal_False; 177 // sal_Bool bCharsBehindInsertPos = ( aSel.Min().GetIndex() < aSel.Min().GetNode()->Len() ) ? sal_True : sal_False; 178 179 // Der SvRTF-Parser erwartet, dass das Which-Mapping am uebergebenen Pool, 180 // nicht an einem Secondary haengt. 181 SfxItemPool* pPool = &aEditDoc.GetItemPool(); 182 while ( pPool->GetSecondaryPool() && !pPool->GetName().EqualsAscii( "EditEngineItemPool" ) ) 183 { 184 pPool = pPool->GetSecondaryPool(); 185 186 } 187 DBG_ASSERT( pPool && pPool->GetName().EqualsAscii( "EditEngineItemPool" ), "ReadRTF: Kein EditEnginePool!" ); 188 189 EditRTFParserRef xPrsr = new EditRTFParser( rInput, aSel, *pPool, this ); 190 SvParserState eState = xPrsr->CallParser(); 191 if ( ( eState != SVPAR_ACCEPTED ) && ( !rInput.GetError() ) ) 192 { 193 rInput.SetError( EE_READWRITE_WRONGFORMAT ); 194 return aSel.Min(); 195 } 196 return xPrsr->GetCurPaM(); 197 #else 198 return EditPaM(); 199 #endif 200 } 201 202 EditPaM ImpEditEngine::ReadHTML( SvStream& rInput, const String& rBaseURL, EditSelection aSel, SvKeyValueIterator* pHTTPHeaderAttrs ) 203 { 204 #ifndef SVX_LIGHT 205 206 if ( aSel.HasRange() ) 207 aSel = ImpDeleteSelection( aSel ); 208 209 // sal_Bool bCharsBeforeInsertPos = ( aSel.Min().GetIndex() ) ? sal_True : sal_False; 210 // sal_Bool bCharsBehindInsertPos = ( aSel.Min().GetIndex() < aSel.Min().GetNode()->Len() ) ? sal_True : sal_False; 211 212 EditHTMLParserRef xPrsr = new EditHTMLParser( rInput, rBaseURL, pHTTPHeaderAttrs ); 213 SvParserState eState = xPrsr->CallParser( this, aSel.Max() ); 214 if ( ( eState != SVPAR_ACCEPTED ) && ( !rInput.GetError() ) ) 215 { 216 rInput.SetError( EE_READWRITE_WRONGFORMAT ); 217 return aSel.Min(); 218 } 219 return xPrsr->GetCurSelection().Max(); 220 #else 221 return EditPaM(); 222 #endif 223 } 224 225 EditPaM ImpEditEngine::ReadBin( SvStream& rInput, EditSelection aSel ) 226 { 227 // Einfach ein temporaeres TextObject missbrauchen... 228 EditTextObject* pObj = EditTextObject::Create( rInput, NULL ); 229 230 EditPaM aLastPaM = aSel.Max(); 231 if ( pObj ) 232 aLastPaM = InsertText( *pObj, aSel ).Max(); 233 234 delete pObj; 235 return aLastPaM; 236 } 237 238 #ifndef SVX_LIGHT 239 void ImpEditEngine::Write( SvStream& rOutput, EETextFormat eFormat, EditSelection aSel ) 240 { 241 if ( !rOutput.IsWritable() ) 242 rOutput.SetError( SVSTREAM_WRITE_ERROR ); 243 244 if ( !rOutput.GetError() ) 245 { 246 if ( eFormat == EE_FORMAT_TEXT ) 247 WriteText( rOutput, aSel ); 248 else if ( eFormat == EE_FORMAT_RTF ) 249 WriteRTF( rOutput, aSel ); 250 else if ( eFormat == EE_FORMAT_XML ) 251 WriteXML( rOutput, aSel ); 252 else if ( eFormat == EE_FORMAT_HTML ) 253 WriteHTML( rOutput, aSel ); 254 else if ( eFormat == EE_FORMAT_BIN) 255 WriteBin( rOutput, aSel ); 256 else 257 { 258 DBG_ERROR( "Write: Unbekanntes Format" ); 259 } 260 } 261 } 262 #endif 263 264 sal_uInt32 ImpEditEngine::WriteText( SvStream& rOutput, EditSelection aSel ) 265 { 266 sal_uInt16 nStartNode, nEndNode; 267 sal_Bool bRange = aSel.HasRange(); 268 if ( bRange ) 269 { 270 aSel.Adjust( aEditDoc ); 271 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); 272 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); 273 } 274 else 275 { 276 nStartNode = 0; 277 nEndNode = aEditDoc.Count()-1; 278 } 279 280 // ueber die Absaetze iterieren... 281 for ( sal_uInt16 nNode = nStartNode; nNode <= nEndNode; nNode++ ) 282 { 283 ContentNode* pNode = aEditDoc.GetObject( nNode ); 284 DBG_ASSERT( pNode, "Node nicht gefunden: Search&Replace" ); 285 286 sal_uInt16 nStartPos = 0; 287 sal_uInt16 nEndPos = pNode->Len(); 288 if ( bRange ) 289 { 290 if ( nNode == nStartNode ) 291 nStartPos = aSel.Min().GetIndex(); 292 if ( nNode == nEndNode ) // kann auch == nStart sein! 293 nEndPos = aSel.Max().GetIndex(); 294 } 295 XubString aTmpStr = aEditDoc.GetParaAsString( pNode, nStartPos, nEndPos ); 296 rOutput.WriteByteStringLine( aTmpStr ); 297 } 298 299 return rOutput.GetError(); 300 } 301 302 sal_Bool ImpEditEngine::WriteItemListAsRTF( ItemList& rLst, SvStream& rOutput, sal_uInt16 nPara, sal_uInt16 nPos, 303 SvxFontTable& rFontTable, SvxColorList& rColorList ) 304 { 305 const SfxPoolItem* pAttrItem = rLst.First(); 306 while ( pAttrItem ) 307 { 308 WriteItemAsRTF( *pAttrItem, rOutput, nPara, nPos,rFontTable, rColorList ); 309 pAttrItem = rLst.Next(); 310 } 311 return ( rLst.Count() ? sal_True : sal_False ); 312 } 313 314 void lcl_FindValidAttribs( ItemList& rLst, ContentNode* pNode, sal_uInt16 nIndex, sal_uInt16 nScriptType ) 315 { 316 sal_uInt16 nAttr = 0; 317 EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); 318 while ( pAttr && ( pAttr->GetStart() <= nIndex ) ) 319 { 320 // Start wird in While ueberprueft... 321 if ( pAttr->GetEnd() > nIndex ) 322 { 323 if ( IsScriptItemValid( pAttr->GetItem()->Which(), nScriptType ) ) 324 rLst.Insert( pAttr->GetItem(), LIST_APPEND ); 325 } 326 nAttr++; 327 pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); 328 } 329 } 330 331 sal_uInt32 ImpEditEngine::WriteBin( SvStream& rOutput, EditSelection aSel, sal_Bool bStoreUnicodeStrings ) const 332 { 333 BinTextObject* pObj = (BinTextObject*)CreateBinTextObject( aSel, NULL ); 334 pObj->StoreUnicodeStrings( bStoreUnicodeStrings ); 335 pObj->Store( rOutput ); 336 delete pObj; 337 return 0; 338 } 339 340 #ifndef SVX_LIGHT 341 sal_uInt32 ImpEditEngine::WriteXML( SvStream& rOutput, EditSelection aSel ) 342 { 343 ESelection aESel = CreateESel( aSel ); 344 345 SvxWriteXML( *GetEditEnginePtr(), rOutput, aESel ); 346 347 return 0; 348 } 349 #endif 350 351 static sal_uInt16 getStylePos( const SfxStyles& rStyles, SfxStyleSheet* pSheet ) 352 { 353 sal_uInt16 nNumber = 0; 354 SfxStyles::const_iterator iter( rStyles.begin() ); 355 while( iter != rStyles.end() ) 356 { 357 if( (*iter++).get() == pSheet ) 358 return nNumber; 359 ++nNumber; 360 } 361 return 0; 362 } 363 364 sal_uInt32 ImpEditEngine::WriteRTF( SvStream& rOutput, EditSelection aSel ) 365 { 366 #ifndef SVX_LIGHT 367 DBG_ASSERT( GetUpdateMode(), "WriteRTF bei UpdateMode = sal_False!" ); 368 CheckIdleFormatter(); 369 if ( !IsFormatted() ) 370 FormatDoc(); 371 372 sal_uInt16 nStartNode, nEndNode; 373 aSel.Adjust( aEditDoc ); 374 375 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); 376 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); 377 378 // RTF-Vorspann... 379 rOutput << '{' ; 380 381 rOutput << OOO_STRING_SVTOOLS_RTF_RTF; 382 383 rOutput << OOO_STRING_SVTOOLS_RTF_ANSI; 384 rtl_TextEncoding eDestEnc = RTL_TEXTENCODING_MS_1252; 385 386 // Fonttabelle erzeugen und rausschreiben... 387 SvxFontTable aFontTable; 388 // DefaultFont muss ganz vorne stehen, damit DEF-Font im RTF 389 aFontTable.Insert( 0, new SvxFontItem( (const SvxFontItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_FONTINFO ) ) ); 390 aFontTable.Insert( 1, new SvxFontItem( (const SvxFontItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_FONTINFO_CJK ) ) ); 391 aFontTable.Insert( 2, new SvxFontItem( (const SvxFontItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_FONTINFO_CTL ) ) ); 392 for ( sal_uInt16 nScriptType = 0; nScriptType < 3; nScriptType++ ) 393 { 394 sal_uInt16 nWhich = EE_CHAR_FONTINFO; 395 if ( nScriptType == 1 ) 396 nWhich = EE_CHAR_FONTINFO_CJK; 397 else if ( nScriptType == 2 ) 398 nWhich = EE_CHAR_FONTINFO_CTL; 399 400 sal_uInt32 i = 0; 401 SvxFontItem* pFontItem = (SvxFontItem*)aEditDoc.GetItemPool().GetItem2( nWhich, i ); 402 while ( pFontItem ) 403 { 404 bool bAlreadyExist = false; 405 sal_uLong nTestMax = nScriptType ? aFontTable.Count() : 1; 406 for ( sal_uLong nTest = 0; !bAlreadyExist && ( nTest < nTestMax ); nTest++ ) 407 { 408 bAlreadyExist = *aFontTable.Get( nTest ) == *pFontItem; 409 } 410 411 if ( !bAlreadyExist ) 412 aFontTable.Insert( aFontTable.Count(), new SvxFontItem( *pFontItem ) ); 413 414 pFontItem = (SvxFontItem*)aEditDoc.GetItemPool().GetItem2( nWhich, ++i ); 415 } 416 } 417 418 rOutput << endl << '{' << OOO_STRING_SVTOOLS_RTF_FONTTBL; 419 sal_uInt16 j; 420 for ( j = 0; j < aFontTable.Count(); j++ ) 421 { 422 SvxFontItem* pFontItem = aFontTable.Get( j ); 423 rOutput << '{'; 424 rOutput << OOO_STRING_SVTOOLS_RTF_F; 425 rOutput.WriteNumber( j ); 426 switch ( pFontItem->GetFamily() ) 427 { 428 case FAMILY_DONTKNOW: rOutput << OOO_STRING_SVTOOLS_RTF_FNIL; 429 break; 430 case FAMILY_DECORATIVE: rOutput << OOO_STRING_SVTOOLS_RTF_FDECOR; 431 break; 432 case FAMILY_MODERN: rOutput << OOO_STRING_SVTOOLS_RTF_FMODERN; 433 break; 434 case FAMILY_ROMAN: rOutput << OOO_STRING_SVTOOLS_RTF_FROMAN; 435 break; 436 case FAMILY_SCRIPT: rOutput << OOO_STRING_SVTOOLS_RTF_FSCRIPT; 437 break; 438 case FAMILY_SWISS: rOutput << OOO_STRING_SVTOOLS_RTF_FSWISS; 439 break; 440 default: 441 break; 442 } 443 rOutput << OOO_STRING_SVTOOLS_RTF_FPRQ; 444 sal_uInt16 nVal = 0; 445 switch( pFontItem->GetPitch() ) 446 { 447 case PITCH_FIXED: nVal = 1; break; 448 case PITCH_VARIABLE: nVal = 2; break; 449 default: 450 break; 451 } 452 rOutput.WriteNumber( nVal ); 453 454 CharSet eChrSet = pFontItem->GetCharSet(); 455 DBG_ASSERT( eChrSet != 9, "SystemCharSet?!" ); 456 if( RTL_TEXTENCODING_DONTKNOW == eChrSet ) 457 eChrSet = gsl_getSystemTextEncoding(); 458 rOutput << OOO_STRING_SVTOOLS_RTF_FCHARSET; 459 rOutput.WriteNumber( rtl_getBestWindowsCharsetFromTextEncoding( eChrSet ) ); 460 461 rOutput << ' '; 462 RTFOutFuncs::Out_String( rOutput, pFontItem->GetFamilyName(), eDestEnc ); 463 rOutput << ";}"; 464 } 465 rOutput << '}'; 466 rOutput << endl; 467 468 // ColorList rausschreiben... 469 SvxColorList aColorList; 470 sal_uInt32 i = 0; 471 SvxColorItem* pColorItem = (SvxColorItem*)aEditDoc.GetItemPool().GetItem2( EE_CHAR_COLOR, i ); 472 while ( pColorItem ) 473 { 474 sal_uInt32 nPos = i; 475 if ( pColorItem->GetValue() == COL_AUTO ) 476 nPos = 0; 477 aColorList.Insert( new SvxColorItem( *pColorItem ), nPos ); 478 pColorItem = (SvxColorItem*)aEditDoc.GetItemPool().GetItem2( EE_CHAR_COLOR, ++i ); 479 } 480 aColorList.Insert( new SvxColorItem( (const SvxColorItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_COLOR) ), i ); 481 482 rOutput << '{' << OOO_STRING_SVTOOLS_RTF_COLORTBL; 483 for ( j = 0; j < aColorList.Count(); j++ ) 484 { 485 pColorItem = aColorList.GetObject( j ); 486 if ( !j || ( pColorItem->GetValue() != COL_AUTO ) ) 487 { 488 rOutput << OOO_STRING_SVTOOLS_RTF_RED; 489 rOutput.WriteNumber( pColorItem->GetValue().GetRed() ); 490 rOutput << OOO_STRING_SVTOOLS_RTF_GREEN; 491 rOutput.WriteNumber( pColorItem->GetValue().GetGreen() ); 492 rOutput << OOO_STRING_SVTOOLS_RTF_BLUE; 493 rOutput.WriteNumber( pColorItem->GetValue().GetBlue() ); 494 } 495 rOutput << ';'; 496 } 497 rOutput << '}'; 498 rOutput << endl; 499 500 // StyleSheets... 501 if ( GetStyleSheetPool() ) 502 { 503 sal_uInt16 nStyles = (sal_uInt16)GetStyleSheetPool()->GetStyles().size(); 504 if ( nStyles ) 505 { 506 rOutput << '{' << OOO_STRING_SVTOOLS_RTF_STYLESHEET; 507 508 for ( sal_uInt16 nStyle = 0; nStyle < nStyles; nStyle++ ) 509 { 510 511 SfxStyleSheet* pStyle = (SfxStyleSheet*)GetStyleSheetPool()->GetStyles()[ nStyle ].get(); 512 513 rOutput << endl << '{' << OOO_STRING_SVTOOLS_RTF_S; 514 sal_uInt16 nNumber = (sal_uInt16) (nStyle + 1); 515 rOutput.WriteNumber( nNumber ); 516 517 // Attribute, auch aus Parent! 518 for ( sal_uInt16 nParAttr = EE_PARA_START; nParAttr <= EE_CHAR_END; nParAttr++ ) 519 { 520 if ( pStyle->GetItemSet().GetItemState( nParAttr ) == SFX_ITEM_ON ) 521 { 522 const SfxPoolItem& rItem = pStyle->GetItemSet().Get( nParAttr ); 523 WriteItemAsRTF( rItem, rOutput, 0, 0, aFontTable, aColorList ); 524 } 525 } 526 527 // Parent...(nur wenn noetig) 528 if ( pStyle->GetParent().Len() && ( pStyle->GetParent() != pStyle->GetName() ) ) 529 { 530 SfxStyleSheet* pParent = (SfxStyleSheet*)GetStyleSheetPool()->Find( pStyle->GetParent(), pStyle->GetFamily() ); 531 DBG_ASSERT( pParent, "Parent nicht gefunden!" ); 532 rOutput << OOO_STRING_SVTOOLS_RTF_SBASEDON; 533 nNumber = (sal_uInt16) getStylePos( GetStyleSheetPool()->GetStyles(), pParent ) + 1; 534 rOutput.WriteNumber( nNumber ); 535 } 536 537 // Folgevorlage...(immer) 538 SfxStyleSheet* pNext = pStyle; 539 if ( pStyle->GetFollow().Len() && ( pStyle->GetFollow() != pStyle->GetName() ) ) 540 pNext = (SfxStyleSheet*)GetStyleSheetPool()->Find( pStyle->GetFollow(), pStyle->GetFamily() ); 541 542 DBG_ASSERT( pNext, "Naechsten nicht gefunden!" ); 543 rOutput << OOO_STRING_SVTOOLS_RTF_SNEXT; 544 nNumber = (sal_uInt16) getStylePos( GetStyleSheetPool()->GetStyles(), pNext ) + 1; 545 rOutput.WriteNumber( nNumber ); 546 547 // Namen der Vorlage... 548 rOutput << " " << ByteString( pStyle->GetName(), eDestEnc ).GetBuffer(); 549 rOutput << ";}"; 550 } 551 rOutput << '}'; 552 rOutput << endl; 553 } 554 } 555 556 // Die Pool-Defaults vorweg schreiben... 557 rOutput << '{' << OOO_STRING_SVTOOLS_RTF_IGNORE << "\\EditEnginePoolDefaults"; 558 for ( sal_uInt16 nPoolDefItem = EE_PARA_START; nPoolDefItem <= EE_CHAR_END; nPoolDefItem++) 559 { 560 const SfxPoolItem& rItem = aEditDoc.GetItemPool().GetDefaultItem( nPoolDefItem ); 561 WriteItemAsRTF( rItem, rOutput, 0, 0, aFontTable, aColorList ); 562 } 563 rOutput << '}' << endl; 564 565 // Def-Hoehe vorweg, da sonst 12Pt 566 // Doch nicht, onst in jedem Absatz hart! 567 // SfxItemSet aTmpSet( GetEmptyItemSet() ); 568 // const SvxFontHeightItem& rDefFontHeight = (const SvxFontHeightItem&)aTmpSet.Get( EE_CHAR_FONTHEIGHT ); 569 // WriteItemAsRTF( rDefFontHeight, rOutput, aFontTable, aColorList ); 570 // rOutput << '{' << OOO_STRING_SVTOOLS_RTF_IGNORE << "\\EditEnginePoolDefaultHeight}" << endl; 571 572 // DefTab: 573 MapMode aTwpMode( MAP_TWIP ); 574 sal_uInt16 nDefTabTwps = (sal_uInt16) GetRefDevice()->LogicToLogic( 575 Point( aEditDoc.GetDefTab(), 0 ), 576 &GetRefMapMode(), &aTwpMode ).X(); 577 rOutput << OOO_STRING_SVTOOLS_RTF_DEFTAB; 578 rOutput.WriteNumber( nDefTabTwps ); 579 rOutput << endl; 580 581 // ueber die Absaetze iterieren... 582 rOutput << '{' << endl; 583 for ( sal_uInt16 nNode = nStartNode; nNode <= nEndNode; nNode++ ) 584 { 585 ContentNode* pNode = aEditDoc.SaveGetObject( nNode ); 586 DBG_ASSERT( pNode, "Node nicht gefunden: Search&Replace" ); 587 588 // Die Absatzattribute vorweg... 589 sal_Bool bAttr = sal_False; 590 591 // Vorlage ? 592 if ( pNode->GetStyleSheet() ) 593 { 594 // Nummer der Vorlage 595 rOutput << OOO_STRING_SVTOOLS_RTF_S; 596 sal_uInt16 nNumber = (sal_uInt16) getStylePos( GetStyleSheetPool()->GetStyles(), pNode->GetStyleSheet() ) + 1; 597 rOutput.WriteNumber( nNumber ); 598 599 // Alle Attribute 600 // Attribute, auch aus Parent! 601 for ( sal_uInt16 nParAttr = EE_PARA_START; nParAttr <= EE_CHAR_END; nParAttr++ ) 602 { 603 if ( pNode->GetStyleSheet()->GetItemSet().GetItemState( nParAttr ) == SFX_ITEM_ON ) 604 { 605 const SfxPoolItem& rItem = pNode->GetStyleSheet()->GetItemSet().Get( nParAttr ); 606 WriteItemAsRTF( rItem, rOutput, nNode, 0, aFontTable, aColorList ); 607 bAttr = sal_True; 608 } 609 } 610 } 611 612 for ( sal_uInt16 nParAttr = EE_PARA_START; nParAttr <= EE_CHAR_END; nParAttr++ ) 613 { 614 // const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItem( nParAttr ); 615 // Jetzt, wo StyleSheet-Verarbeitung, nur noch harte Absatzattribute! 616 if ( pNode->GetContentAttribs().GetItems().GetItemState( nParAttr ) == SFX_ITEM_ON ) 617 { 618 const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItems().Get( nParAttr ); 619 WriteItemAsRTF( rItem, rOutput, nNode, 0, aFontTable, aColorList ); 620 bAttr = sal_True; 621 } 622 } 623 if ( bAttr ) 624 rOutput << ' '; // Separator 625 626 ItemList aAttribItems; 627 ParaPortion* pParaPortion = FindParaPortion( pNode ); 628 DBG_ASSERT( pParaPortion, "Portion nicht gefunden: WriteRTF" ); 629 630 sal_uInt16 nIndex = 0; 631 sal_uInt16 nStartPos = 0; 632 sal_uInt16 nEndPos = pNode->Len(); 633 sal_uInt16 nStartPortion = 0; 634 sal_uInt16 nEndPortion = (sal_uInt16)pParaPortion->GetTextPortions().Count() - 1; 635 sal_Bool bFinishPortion = sal_False; 636 sal_uInt16 nPortionStart; 637 638 if ( nNode == nStartNode ) 639 { 640 nStartPos = aSel.Min().GetIndex(); 641 nStartPortion = pParaPortion->GetTextPortions().FindPortion( nStartPos, nPortionStart ); 642 if ( nStartPos != 0 ) 643 { 644 aAttribItems.Clear(); 645 lcl_FindValidAttribs( aAttribItems, pNode, nStartPos, GetScriptType( EditPaM( pNode, 0 ) ) ); 646 if ( aAttribItems.Count() ) 647 { 648 // Diese Attribute duerfen nicht fuer den gesamten 649 // Absatz gelten: 650 rOutput << '{'; 651 WriteItemListAsRTF( aAttribItems, rOutput, nNode, nStartPos, aFontTable, aColorList ); 652 bFinishPortion = sal_True; 653 } 654 aAttribItems.Clear(); 655 } 656 } 657 if ( nNode == nEndNode ) // kann auch == nStart sein! 658 { 659 nEndPos = aSel.Max().GetIndex(); 660 nEndPortion = pParaPortion->GetTextPortions().FindPortion( nEndPos, nPortionStart ); 661 } 662 663 EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature( nIndex ); 664 // Bei 0 anfangen, damit der Index richtig ist... 665 666 for ( sal_uInt16 n = 0; n <= nEndPortion; n++ ) 667 { 668 TextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject(n); 669 if ( n < nStartPortion ) 670 { 671 nIndex = nIndex + pTextPortion->GetLen(); 672 continue; 673 } 674 675 if ( pNextFeature && ( pNextFeature->GetStart() == nIndex ) && ( pNextFeature->GetItem()->Which() != EE_FEATURE_FIELD ) ) 676 { 677 WriteItemAsRTF( *pNextFeature->GetItem(), rOutput, nNode, nIndex, aFontTable, aColorList ); 678 pNextFeature = pNode->GetCharAttribs().FindFeature( pNextFeature->GetStart() + 1 ); 679 } 680 else 681 { 682 aAttribItems.Clear(); 683 sal_uInt16 nScriptType = GetScriptType( EditPaM( pNode, nIndex+1 ) ); 684 if ( !n || IsScriptChange( EditPaM( pNode, nIndex ) ) ) 685 { 686 SfxItemSet aAttribs = GetAttribs( nNode, nIndex+1, nIndex+1 ); 687 aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_FONTINFO, nScriptType ) ), LIST_APPEND ); 688 aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType ) ), LIST_APPEND ); 689 aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_WEIGHT, nScriptType ) ), LIST_APPEND ); 690 aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_ITALIC, nScriptType ) ), LIST_APPEND ); 691 aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ) ), LIST_APPEND ); 692 } 693 // #96298# Insert hard attribs AFTER CJK attribs... 694 lcl_FindValidAttribs( aAttribItems, pNode, nIndex, nScriptType ); 695 696 rOutput << '{'; 697 if ( WriteItemListAsRTF( aAttribItems, rOutput, nNode, nIndex, aFontTable, aColorList ) ) 698 rOutput << ' '; 699 700 sal_uInt16 nS = nIndex; 701 sal_uInt16 nE = nIndex + pTextPortion->GetLen(); 702 if ( n == nStartPortion ) 703 nS = nStartPos; 704 if ( n == nEndPortion ) 705 nE = nEndPos; 706 707 XubString aRTFStr = aEditDoc.GetParaAsString( pNode, nS, nE); 708 RTFOutFuncs::Out_String( rOutput, aRTFStr, eDestEnc ); 709 rOutput << '}'; 710 } 711 if ( bFinishPortion ) 712 { 713 rOutput << '}'; 714 bFinishPortion = sal_False; 715 } 716 717 nIndex = nIndex + pTextPortion->GetLen(); 718 } 719 720 rOutput << OOO_STRING_SVTOOLS_RTF_PAR << OOO_STRING_SVTOOLS_RTF_PARD << OOO_STRING_SVTOOLS_RTF_PLAIN;; 721 rOutput << endl; 722 } 723 // RTF-Nachspann... 724 rOutput << "}}"; // 1xKlammerung Absaetze, 1x Klammerung RTF-Dokument 725 rOutput.Flush(); 726 727 #if defined (EDITDEBUG) && !defined( UNX ) 728 { 729 SvFileStream aStream( String( RTL_CONSTASCII_USTRINGPARAM ( "d:\\rtf_out.rtf" ) ), STREAM_WRITE|STREAM_TRUNC ); 730 sal_uLong nP = rOutput.Tell(); 731 rOutput.Seek( 0 ); 732 aStream << rOutput; 733 rOutput.Seek( nP ); 734 } 735 #endif 736 737 return rOutput.GetError(); 738 #else 739 return 0; 740 #endif 741 } 742 743 744 void ImpEditEngine::WriteItemAsRTF( const SfxPoolItem& rItem, SvStream& rOutput, sal_uInt16 nPara, sal_uInt16 nPos, 745 SvxFontTable& rFontTable, SvxColorList& rColorList ) 746 { 747 sal_uInt16 nWhich = rItem.Which(); 748 switch ( nWhich ) 749 { 750 case EE_PARA_WRITINGDIR: 751 { 752 const SvxFrameDirectionItem& rWritingMode = (const SvxFrameDirectionItem&)rItem; 753 if ( rWritingMode.GetValue() == FRMDIR_HORI_RIGHT_TOP ) 754 rOutput << "\\rtlpar"; 755 else 756 rOutput << "\\ltrpar"; 757 } 758 break; 759 case EE_PARA_OUTLLEVEL: 760 { 761 sal_Int16 nLevel = ((const SfxInt16Item&)rItem).GetValue(); 762 if( nLevel >= 0 ) 763 { 764 rOutput << "\\level"; 765 rOutput.WriteNumber( nLevel ); 766 } 767 } 768 break; 769 case EE_PARA_OUTLLRSPACE: 770 case EE_PARA_LRSPACE: 771 { 772 // const ContentNode *pNode = aEditDoc.GetObject( nPara ); 773 774 rOutput << OOO_STRING_SVTOOLS_RTF_FI; 775 short nTxtFirst = ((const SvxLRSpaceItem&)rItem).GetTxtFirstLineOfst(); 776 nTxtFirst = (short)LogicToTwips( nTxtFirst ); 777 rOutput.WriteNumber( nTxtFirst ); 778 rOutput << OOO_STRING_SVTOOLS_RTF_LI; 779 sal_uInt16 nTxtLeft = static_cast< sal_uInt16 >(((const SvxLRSpaceItem&)rItem).GetTxtLeft()); 780 nTxtLeft = (sal_uInt16)LogicToTwips( nTxtLeft ); 781 rOutput.WriteNumber( nTxtLeft ); 782 rOutput << OOO_STRING_SVTOOLS_RTF_RI; 783 sal_uInt32 nTxtRight = ((const SvxLRSpaceItem&)rItem).GetRight(); 784 nTxtRight = LogicToTwips( nTxtRight); 785 rOutput.WriteNumber( nTxtRight ); 786 } 787 break; 788 case EE_PARA_ULSPACE: 789 { 790 rOutput << OOO_STRING_SVTOOLS_RTF_SB; 791 sal_uInt16 nUpper = ((const SvxULSpaceItem&)rItem).GetUpper(); 792 nUpper = (sal_uInt16)LogicToTwips( nUpper ); 793 rOutput.WriteNumber( nUpper ); 794 rOutput << OOO_STRING_SVTOOLS_RTF_SA; 795 sal_uInt16 nLower = ((const SvxULSpaceItem&)rItem).GetLower(); 796 nLower = (sal_uInt16)LogicToTwips( nLower ); 797 rOutput.WriteNumber( nLower ); 798 } 799 break; 800 case EE_PARA_SBL: 801 { 802 rOutput << OOO_STRING_SVTOOLS_RTF_SL; 803 long nVal = ((const SvxLineSpacingItem&)rItem).GetLineHeight(); 804 char cMult = '0'; 805 if ( ((const SvxLineSpacingItem&)rItem).GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP ) 806 { 807 // Woher kriege ich jetzt den Wert? 808 // Der SwRTF-Parser geht von einem 240er Font aus! 809 nVal = ((const SvxLineSpacingItem&)rItem).GetPropLineSpace(); 810 nVal *= 240; 811 nVal /= 100; 812 cMult = '1'; 813 } 814 rOutput.WriteNumber( nVal ); 815 rOutput << OOO_STRING_SVTOOLS_RTF_SLMULT << cMult; 816 } 817 break; 818 case EE_PARA_JUST: 819 { 820 SvxAdjust eJustification = ((const SvxAdjustItem&)rItem).GetAdjust(); 821 switch ( eJustification ) 822 { 823 case SVX_ADJUST_CENTER: rOutput << OOO_STRING_SVTOOLS_RTF_QC; 824 break; 825 case SVX_ADJUST_RIGHT: rOutput << OOO_STRING_SVTOOLS_RTF_QR; 826 break; 827 default: rOutput << OOO_STRING_SVTOOLS_RTF_QL; 828 break; 829 } 830 } 831 break; 832 case EE_PARA_TABS: 833 { 834 const SvxTabStopItem& rTabs = (const SvxTabStopItem&) rItem; 835 for ( sal_uInt16 i = 0; i < rTabs.Count(); i++ ) 836 { 837 const SvxTabStop& rTab = rTabs[i]; 838 rOutput << OOO_STRING_SVTOOLS_RTF_TX; 839 rOutput.WriteNumber( LogicToTwips( rTab.GetTabPos() ) ); 840 } 841 } 842 break; 843 case EE_CHAR_COLOR: 844 { 845 sal_uInt32 n = rColorList.GetId( (const SvxColorItem&)rItem ); 846 rOutput << OOO_STRING_SVTOOLS_RTF_CF; 847 rOutput.WriteNumber( n ); 848 } 849 break; 850 case EE_CHAR_FONTINFO: 851 case EE_CHAR_FONTINFO_CJK: 852 case EE_CHAR_FONTINFO_CTL: 853 { 854 sal_uInt32 n = rFontTable.GetId( (const SvxFontItem&)rItem ); 855 rOutput << OOO_STRING_SVTOOLS_RTF_F; 856 rOutput.WriteNumber( n ); 857 } 858 break; 859 case EE_CHAR_FONTHEIGHT: 860 case EE_CHAR_FONTHEIGHT_CJK: 861 case EE_CHAR_FONTHEIGHT_CTL: 862 { 863 rOutput << OOO_STRING_SVTOOLS_RTF_FS; 864 long nHeight = ((const SvxFontHeightItem&)rItem).GetHeight(); 865 nHeight = LogicToTwips( nHeight ); 866 // Twips => HalfPoints 867 nHeight /= 10; 868 rOutput.WriteNumber( nHeight ); 869 } 870 break; 871 case EE_CHAR_WEIGHT: 872 case EE_CHAR_WEIGHT_CJK: 873 case EE_CHAR_WEIGHT_CTL: 874 { 875 FontWeight e = ((const SvxWeightItem&)rItem).GetWeight(); 876 switch ( e ) 877 { 878 case WEIGHT_BOLD: rOutput << OOO_STRING_SVTOOLS_RTF_B; break; 879 default: rOutput << OOO_STRING_SVTOOLS_RTF_B << '0'; break; 880 } 881 } 882 break; 883 case EE_CHAR_UNDERLINE: 884 { 885 // muesste bei WordLineMode ggf. ulw werden, 886 // aber die Information fehlt hier 887 FontUnderline e = ((const SvxUnderlineItem&)rItem).GetLineStyle(); 888 switch ( e ) 889 { 890 case UNDERLINE_NONE: rOutput << OOO_STRING_SVTOOLS_RTF_ULNONE; break; 891 case UNDERLINE_SINGLE: rOutput << OOO_STRING_SVTOOLS_RTF_UL; break; 892 case UNDERLINE_DOUBLE: rOutput << OOO_STRING_SVTOOLS_RTF_ULDB; break; 893 case UNDERLINE_DOTTED: rOutput << OOO_STRING_SVTOOLS_RTF_ULD; break; 894 default: 895 break; 896 } 897 } 898 break; 899 case EE_CHAR_OVERLINE: 900 { 901 FontUnderline e = ((const SvxOverlineItem&)rItem).GetLineStyle(); 902 switch ( e ) 903 { 904 case UNDERLINE_NONE: rOutput << OOO_STRING_SVTOOLS_RTF_OLNONE; break; 905 case UNDERLINE_SINGLE: rOutput << OOO_STRING_SVTOOLS_RTF_OL; break; 906 case UNDERLINE_DOUBLE: rOutput << OOO_STRING_SVTOOLS_RTF_OLDB; break; 907 case UNDERLINE_DOTTED: rOutput << OOO_STRING_SVTOOLS_RTF_OLD; break; 908 default: 909 break; 910 } 911 } 912 break; 913 case EE_CHAR_STRIKEOUT: 914 { 915 FontStrikeout e = ((const SvxCrossedOutItem&)rItem).GetStrikeout(); 916 switch ( e ) 917 { 918 case STRIKEOUT_SINGLE: 919 case STRIKEOUT_DOUBLE: rOutput << OOO_STRING_SVTOOLS_RTF_STRIKE; break; 920 case STRIKEOUT_NONE: rOutput << OOO_STRING_SVTOOLS_RTF_STRIKE << '0'; break; 921 default: 922 break; 923 } 924 } 925 break; 926 case EE_CHAR_ITALIC: 927 case EE_CHAR_ITALIC_CJK: 928 case EE_CHAR_ITALIC_CTL: 929 { 930 FontItalic e = ((const SvxPostureItem&)rItem).GetPosture(); 931 switch ( e ) 932 { 933 case ITALIC_OBLIQUE: 934 case ITALIC_NORMAL: rOutput << OOO_STRING_SVTOOLS_RTF_I; break; 935 case ITALIC_NONE: rOutput << OOO_STRING_SVTOOLS_RTF_I << '0'; break; 936 default: 937 break; 938 } 939 } 940 break; 941 case EE_CHAR_OUTLINE: 942 { 943 rOutput << OOO_STRING_SVTOOLS_RTF_OUTL; 944 if ( ((const SvxContourItem&)rItem).GetValue() == 0 ) 945 rOutput << '0'; 946 } 947 break; 948 case EE_CHAR_RELIEF: 949 { 950 sal_uInt16 nRelief = ((const SvxCharReliefItem&)rItem).GetValue(); 951 if ( nRelief == RELIEF_EMBOSSED ) 952 rOutput << OOO_STRING_SVTOOLS_RTF_EMBO; 953 if ( nRelief == RELIEF_ENGRAVED ) 954 rOutput << OOO_STRING_SVTOOLS_RTF_IMPR; 955 } 956 break; 957 case EE_CHAR_EMPHASISMARK: 958 { 959 sal_uInt16 nMark = ((const SvxEmphasisMarkItem&)rItem).GetValue(); 960 if ( nMark == EMPHASISMARK_NONE ) 961 rOutput << OOO_STRING_SVTOOLS_RTF_ACCNONE; 962 else if ( nMark == EMPHASISMARK_SIDE_DOTS ) 963 rOutput << OOO_STRING_SVTOOLS_RTF_ACCCOMMA; 964 else 965 rOutput << OOO_STRING_SVTOOLS_RTF_ACCDOT; 966 } 967 break; 968 case EE_CHAR_SHADOW: 969 { 970 rOutput << OOO_STRING_SVTOOLS_RTF_SHAD; 971 if ( ((const SvxShadowedItem&)rItem).GetValue() == 0 ) 972 rOutput << '0'; 973 } 974 break; 975 case EE_FEATURE_TAB: 976 { 977 rOutput << OOO_STRING_SVTOOLS_RTF_TAB; 978 } 979 break; 980 case EE_FEATURE_LINEBR: 981 { 982 rOutput << OOO_STRING_SVTOOLS_RTF_SL; 983 } 984 break; 985 case EE_CHAR_KERNING: 986 { 987 rOutput << OOO_STRING_SVTOOLS_RTF_EXPNDTW; 988 rOutput.WriteNumber( LogicToTwips( 989 ((const SvxKerningItem&)rItem).GetValue() ) ); 990 } 991 break; 992 case EE_CHAR_PAIRKERNING: 993 { 994 rOutput << OOO_STRING_SVTOOLS_RTF_KERNING; 995 rOutput.WriteNumber( ((const SvxAutoKernItem&)rItem).GetValue() ? 1 : 0 ); 996 } 997 break; 998 case EE_CHAR_ESCAPEMENT: 999 { 1000 SvxFont aFont; 1001 ContentNode* pNode = aEditDoc.GetObject( nPara ); 1002 SeekCursor( pNode, nPos, aFont ); 1003 MapMode aPntMode( MAP_POINT ); 1004 long nFontHeight = GetRefDevice()->LogicToLogic( 1005 aFont.GetSize(), &GetRefMapMode(), &aPntMode ).Height(); 1006 nFontHeight *=2; // HalfPoints 1007 sal_uInt16 nProp = ((const SvxEscapementItem&)rItem).GetProp(); 1008 sal_uInt16 nProp100 = nProp*100; // Fuer SWG-Token Prop in 100tel Prozent. 1009 short nEsc = ((const SvxEscapementItem&)rItem).GetEsc(); 1010 if ( nEsc == DFLT_ESC_AUTO_SUPER ) 1011 { 1012 nEsc = 100 - nProp; 1013 nProp100++; // Eine 1 hinten bedeutet 'automatisch'. 1014 } 1015 else if ( nEsc == DFLT_ESC_AUTO_SUB ) 1016 { 1017 nEsc = sal::static_int_cast< short >( -( 100 - nProp ) ); 1018 nProp100++; 1019 } 1020 // SWG: 1021 if ( nEsc ) 1022 rOutput << "{\\*\\updnprop" << ByteString::CreateFromInt32( nProp100 ).GetBuffer() << '}'; 1023 long nUpDown = nFontHeight * Abs( nEsc ) / 100; 1024 ByteString aUpDown = ByteString::CreateFromInt32( nUpDown ); 1025 if ( nEsc < 0 ) 1026 rOutput << OOO_STRING_SVTOOLS_RTF_DN << aUpDown.GetBuffer(); 1027 else if ( nEsc > 0 ) 1028 rOutput << OOO_STRING_SVTOOLS_RTF_UP << aUpDown.GetBuffer(); 1029 } 1030 break; 1031 } 1032 } 1033 1034 sal_uInt32 ImpEditEngine::WriteHTML( SvStream&, EditSelection ) 1035 { 1036 return 0; 1037 } 1038 1039 1040 EditTextObject* ImpEditEngine::CreateTextObject() 1041 { 1042 EditSelection aCompleteSelection; 1043 aCompleteSelection.Min() = aEditDoc.GetStartPaM(); 1044 aCompleteSelection.Max() = aEditDoc.GetEndPaM(); 1045 1046 return CreateTextObject( aCompleteSelection ); 1047 } 1048 1049 EditTextObject* ImpEditEngine::CreateTextObject( EditSelection aSel ) 1050 { 1051 return CreateBinTextObject( aSel, GetEditTextObjectPool(), aStatus.AllowBigObjects(), nBigTextObjectStart ); 1052 } 1053 1054 EditTextObject* ImpEditEngine::CreateBinTextObject( EditSelection aSel, SfxItemPool* pPool, sal_Bool bAllowBigObjects, sal_uInt16 nBigObjectStart ) const 1055 { 1056 BinTextObject* pTxtObj = new BinTextObject( pPool ); 1057 pTxtObj->SetVertical( IsVertical() ); 1058 MapUnit eMapUnit = (MapUnit)aEditDoc.GetItemPool().GetMetric( DEF_METRIC ); 1059 pTxtObj->SetMetric( (sal_uInt16) eMapUnit ); 1060 if ( pTxtObj->IsOwnerOfPool() ) 1061 pTxtObj->GetPool()->SetDefaultMetric( (SfxMapUnit) eMapUnit ); 1062 1063 sal_uInt16 nStartNode, nEndNode; 1064 sal_uInt32 nTextPortions = 0; 1065 1066 aSel.Adjust( aEditDoc ); 1067 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); 1068 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); 1069 1070 sal_Bool bOnlyFullParagraphs = ( aSel.Min().GetIndex() || 1071 ( aSel.Max().GetIndex() < aSel.Max().GetNode()->Len() ) ) ? 1072 sal_False : sal_True; 1073 1074 // Vorlagen werden nicht gespeichert! 1075 // ( Nur Name und Familie, Vorlage selbst muss in App stehen! ) 1076 1077 pTxtObj->SetScriptType( GetScriptType( aSel ) ); 1078 1079 // ueber die Absaetze iterieren... 1080 sal_uInt16 nNode; 1081 for ( nNode = nStartNode; nNode <= nEndNode; nNode++ ) 1082 { 1083 ContentNode* pNode = aEditDoc.SaveGetObject( nNode ); 1084 DBG_ASSERT( pNode, "Node nicht gefunden: Search&Replace" ); 1085 1086 if ( bOnlyFullParagraphs ) 1087 { 1088 ParaPortion* pParaPortion = GetParaPortions()[nNode]; 1089 nTextPortions += pParaPortion->GetTextPortions().Count(); 1090 } 1091 1092 sal_uInt16 nStartPos = 0; 1093 sal_uInt16 nEndPos = pNode->Len(); 1094 1095 sal_Bool bEmptyPara = nEndPos ? sal_False : sal_True; 1096 1097 if ( ( nNode == nStartNode ) && !bOnlyFullParagraphs ) 1098 nStartPos = aSel.Min().GetIndex(); 1099 if ( ( nNode == nEndNode ) && !bOnlyFullParagraphs ) 1100 nEndPos = aSel.Max().GetIndex(); 1101 1102 1103 ContentInfo* pC = pTxtObj->CreateAndInsertContent(); 1104 1105 // Die Absatzattribute... 1106 pC->GetParaAttribs().Set( pNode->GetContentAttribs().GetItems() ); 1107 1108 // Das StyleSheet... 1109 if ( pNode->GetStyleSheet() ) 1110 { 1111 pC->GetStyle() = pNode->GetStyleSheet()->GetName(); 1112 pC->GetFamily() = pNode->GetStyleSheet()->GetFamily(); 1113 } 1114 1115 // Der Text... 1116 pC->GetText() = pNode->Copy( nStartPos, nEndPos-nStartPos ); 1117 1118 // und die Attribute... 1119 sal_uInt16 nAttr = 0; 1120 EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); 1121 while ( pAttr ) 1122 { 1123 // In einem leeren Absatz die Attribute behalten! 1124 if ( bEmptyPara || 1125 ( ( pAttr->GetEnd() > nStartPos ) && ( pAttr->GetStart() < nEndPos ) ) ) 1126 { 1127 XEditAttribute* pX = pTxtObj->CreateAttrib( *pAttr->GetItem(), pAttr->GetStart(), pAttr->GetEnd() ); 1128 // Evtl. korrigieren... 1129 if ( ( nNode == nStartNode ) && ( nStartPos != 0 ) ) 1130 { 1131 pX->GetStart() = ( pX->GetStart() > nStartPos ) ? pX->GetStart()-nStartPos : 0; 1132 pX->GetEnd() = pX->GetEnd() - nStartPos; 1133 1134 } 1135 if ( nNode == nEndNode ) 1136 { 1137 if ( pX->GetEnd() > (nEndPos-nStartPos) ) 1138 pX->GetEnd() = nEndPos-nStartPos; 1139 } 1140 DBG_ASSERT( pX->GetEnd() <= (nEndPos-nStartPos), "CreateBinTextObject: Attribut zu lang!" ); 1141 if ( !pX->GetLen() && !bEmptyPara ) 1142 pTxtObj->DestroyAttrib( pX ); 1143 else 1144 pC->GetAttribs().Insert( pX, pC->GetAttribs().Count() ); 1145 } 1146 nAttr++; 1147 pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); 1148 } 1149 1150 #ifndef SVX_LIGHT 1151 // ggf. Online-Spelling 1152 if ( bAllowBigObjects && bOnlyFullParagraphs && pNode->GetWrongList() ) 1153 pC->SetWrongList( pNode->GetWrongList()->Clone() ); 1154 #endif // !SVX_LIGHT 1155 1156 } 1157 1158 // Bei grossen Textobjekten die PortionInfos merken: 1159 // Schwelle rauf setzen, wenn Olli die Absaetze nicht mehr zerhackt! 1160 if ( bAllowBigObjects && bOnlyFullParagraphs && IsFormatted() && GetUpdateMode() && ( nTextPortions >= nBigObjectStart ) ) 1161 { 1162 XParaPortionList* pXList = new XParaPortionList( GetRefDevice(), aPaperSize.Width() ); 1163 pTxtObj->SetPortionInfo( pXList ); 1164 for ( nNode = nStartNode; nNode <= nEndNode; nNode++ ) 1165 { 1166 ParaPortion* pParaPortion = GetParaPortions()[nNode]; 1167 XParaPortion* pX = new XParaPortion; 1168 pXList->Insert( pX, pXList->Count() ); 1169 1170 pX->nHeight = pParaPortion->GetHeight(); 1171 pX->nFirstLineOffset = pParaPortion->GetFirstLineOffset(); 1172 1173 // Die TextPortions 1174 sal_uInt16 nCount = pParaPortion->GetTextPortions().Count(); 1175 sal_uInt16 n; 1176 for ( n = 0; n < nCount; n++ ) 1177 { 1178 TextPortion* pTextPortion = pParaPortion->GetTextPortions()[n]; 1179 TextPortion* pNew = new TextPortion( *pTextPortion ); 1180 pX->aTextPortions.Insert( pNew, pX->aTextPortions.Count() ); 1181 } 1182 1183 // Die Zeilen 1184 nCount = pParaPortion->GetLines().Count(); 1185 for ( n = 0; n < nCount; n++ ) 1186 { 1187 EditLine* pLine = pParaPortion->GetLines()[n]; 1188 EditLine* pNew = pLine->Clone(); 1189 pX->aLines.Insert( pNew, pX->aLines.Count() ); 1190 } 1191 #ifdef DBG_UTIL 1192 sal_uInt16 nTest; 1193 int nTPLen = 0, nTxtLen = 0; 1194 for ( nTest = pParaPortion->GetTextPortions().Count(); nTest; ) 1195 nTPLen += pParaPortion->GetTextPortions().GetObject( --nTest )->GetLen(); 1196 for ( nTest = pParaPortion->GetLines().Count(); nTest; ) 1197 nTxtLen += pParaPortion->GetLines().GetObject( --nTest )->GetLen(); 1198 DBG_ASSERT( ( nTPLen == pParaPortion->GetNode()->Len() ) && ( nTxtLen == pParaPortion->GetNode()->Len() ), "CreateBinTextObject: ParaPortion not completely formatted!" ); 1199 #endif 1200 } 1201 } 1202 return pTxtObj; 1203 } 1204 1205 void ImpEditEngine::SetText( const EditTextObject& rTextObject ) 1206 { 1207 // Da Setzen eines TextObject ist nicht Undo-faehig! 1208 ResetUndoManager(); 1209 sal_Bool _bUpdate = GetUpdateMode(); 1210 sal_Bool _bUndo = IsUndoEnabled(); 1211 1212 SetText( XubString() ); 1213 EditPaM aPaM = aEditDoc.GetStartPaM(); 1214 1215 SetUpdateMode( sal_False ); 1216 EnableUndo( sal_False ); 1217 1218 InsertText( rTextObject, EditSelection( aPaM, aPaM ) ); 1219 SetVertical( rTextObject.IsVertical() ); 1220 1221 #ifndef SVX_LIGHT 1222 DBG_ASSERT( !HasUndoManager() || !GetUndoManager().GetUndoActionCount(), "Woher kommt das Undo in SetText ?!" ); 1223 #endif 1224 SetUpdateMode( _bUpdate ); 1225 EnableUndo( _bUndo ); 1226 } 1227 1228 EditSelection ImpEditEngine::InsertText( const EditTextObject& rTextObject, EditSelection aSel ) 1229 { 1230 EnterBlockNotifications(); 1231 aSel.Adjust( aEditDoc ); 1232 if ( aSel.HasRange() ) 1233 aSel = ImpDeleteSelection( aSel ); 1234 EditSelection aNewSel = InsertBinTextObject( (BinTextObject&)rTextObject, aSel.Max() ); 1235 LeaveBlockNotifications(); 1236 return aNewSel; 1237 1238 // MT 05/00: InsertBinTextObject direkt hier machen... 1239 } 1240 1241 EditSelection ImpEditEngine::InsertBinTextObject( BinTextObject& rTextObject, EditPaM aPaM ) 1242 { 1243 // Optimieren: 1244 // Kein GetPos undFindParaportion, sondern Index berechnen! 1245 EditSelection aSel( aPaM, aPaM ); 1246 DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "InsertBibTextObject: Selektion kaput!(1)" ); 1247 1248 sal_Bool bUsePortionInfo = sal_False; 1249 // sal_Bool bFields = sal_False; 1250 XParaPortionList* pPortionInfo = rTextObject.GetPortionInfo(); 1251 1252 if ( pPortionInfo && ( (long)pPortionInfo->GetPaperWidth() == aPaperSize.Width() ) 1253 && ( pPortionInfo->GetRefMapMode() == GetRefDevice()->GetMapMode() ) ) 1254 { 1255 if ( ( pPortionInfo->GetRefDevPtr() == (sal_uIntPtr)GetRefDevice() ) || 1256 ( ( pPortionInfo->GetRefDevType() == OUTDEV_VIRDEV ) && 1257 ( GetRefDevice()->GetOutDevType() == OUTDEV_VIRDEV ) ) ) 1258 bUsePortionInfo = sal_True; 1259 } 1260 1261 sal_Bool bConvertItems = sal_False; 1262 MapUnit eSourceUnit = MapUnit(), eDestUnit = MapUnit(); 1263 if ( rTextObject.HasMetric() ) 1264 { 1265 eSourceUnit = (MapUnit)rTextObject.GetMetric(); 1266 eDestUnit = (MapUnit)aEditDoc.GetItemPool().GetMetric( DEF_METRIC ); 1267 if ( eSourceUnit != eDestUnit ) 1268 bConvertItems = sal_True; 1269 } 1270 1271 sal_uInt16 nContents = rTextObject.GetContents().Count(); 1272 sal_uInt16 nPara = aEditDoc.GetPos( aPaM.GetNode() ); 1273 1274 for ( sal_uInt16 n = 0; n < nContents; n++, nPara++ ) 1275 { 1276 ContentInfo* pC = rTextObject.GetContents().GetObject( n ); 1277 sal_Bool bNewContent = aPaM.GetNode()->Len() ? sal_False: sal_True; 1278 sal_uInt16 nStartPos = aPaM.GetIndex(); 1279 1280 aPaM = ImpFastInsertText( aPaM, pC->GetText() ); 1281 1282 ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() ); 1283 DBG_ASSERT( pPortion, "Blinde Portion in FastInsertText" ); 1284 pPortion->MarkInvalid( nStartPos, pC->GetText().Len() ); 1285 1286 // Zeicheattribute... 1287 sal_Bool bAllreadyHasAttribs = aPaM.GetNode()->GetCharAttribs().Count() ? sal_True : sal_False; 1288 sal_uInt16 nNewAttribs = pC->GetAttribs().Count(); 1289 if ( nNewAttribs ) 1290 { 1291 sal_Bool bUpdateFields = sal_False; 1292 for ( sal_uInt16 nAttr = 0; nAttr < nNewAttribs; nAttr++ ) 1293 { 1294 XEditAttribute* pX = pC->GetAttribs().GetObject( nAttr ); 1295 // Kann passieren wenn Absaetze >16K entstehen, dann wird einfach umgebrochen. 1296 if ( pX->GetEnd() <= aPaM.GetNode()->Len() ) 1297 { 1298 if ( !bAllreadyHasAttribs || pX->IsFeature() ) 1299 { 1300 // Normale Attribute gehen dann schneller... 1301 // Features duerfen nicht ueber EditDoc::InsertAttrib 1302 // eingefuegt werden, sie sind bei FastInsertText schon im TextFluss 1303 DBG_ASSERT( pX->GetEnd() <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribut zu gross!" ); 1304 EditCharAttrib* pAttr; 1305 if ( !bConvertItems ) 1306 pAttr = MakeCharAttrib( aEditDoc.GetItemPool(), *(pX->GetItem()), pX->GetStart()+nStartPos, pX->GetEnd()+nStartPos ); 1307 else 1308 { 1309 SfxPoolItem* pNew = pX->GetItem()->Clone(); 1310 ConvertItem( *pNew, eSourceUnit, eDestUnit ); 1311 pAttr = MakeCharAttrib( aEditDoc.GetItemPool(), *pNew, pX->GetStart()+nStartPos, pX->GetEnd()+nStartPos ); 1312 delete pNew; 1313 } 1314 DBG_ASSERT( pAttr->GetEnd() <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribut passt nicht! (1)" ); 1315 aPaM.GetNode()->GetCharAttribs().InsertAttrib( pAttr ); 1316 if ( pAttr->Which() == EE_FEATURE_FIELD ) 1317 bUpdateFields = sal_True; 1318 } 1319 else 1320 { 1321 DBG_ASSERT( pX->GetEnd()+nStartPos <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribut passt nicht! (2)" ); 1322 // Tabs und andere Features koennen nicht ueber InsertAttrib eingefuegt werden: 1323 aEditDoc.InsertAttrib( aPaM.GetNode(), pX->GetStart()+nStartPos, pX->GetEnd()+nStartPos, *pX->GetItem() ); 1324 } 1325 } 1326 } 1327 if ( bUpdateFields ) 1328 UpdateFields(); 1329 1330 // Sonst QuickFormat => Keine Attribute! 1331 pPortion->MarkSelectionInvalid( nStartPos, pC->GetText().Len() ); 1332 } 1333 1334 DBG_ASSERT( CheckOrderedList( aPaM.GetNode()->GetCharAttribs().GetAttribs(), sal_True ), "InsertBinTextObject: Start-Liste verdreht" ); 1335 1336 sal_Bool bParaAttribs = sal_False; 1337 if ( bNewContent || ( ( n > 0 ) && ( n < (nContents-1) ) ) ) 1338 { 1339 bParaAttribs = sal_False; 1340 // #101512# Don't overwrite level/style from existing paragraph in OutlineView 1341 // MT 10/2002: Removed because of #103874#, handled in Outliner::EndPasteOrDropHdl now. 1342 // if ( !aStatus.IsOutliner() || n ) 1343 { 1344 // nur dann Style und ParaAttribs, wenn neuer Absatz, oder 1345 // komplett inneliegender... 1346 bParaAttribs = pC->GetParaAttribs().Count() ? sal_True : sal_False; 1347 if ( GetStyleSheetPool() && pC->GetStyle().Len() ) 1348 { 1349 SfxStyleSheet* pStyle = (SfxStyleSheet*)GetStyleSheetPool()->Find( pC->GetStyle(), pC->GetFamily() ); 1350 DBG_ASSERT( pStyle, "InsertBinTextObject - Style not found!" ); 1351 SetStyleSheet( nPara, pStyle ); 1352 } 1353 if ( !bConvertItems ) 1354 SetParaAttribs( aEditDoc.GetPos( aPaM.GetNode() ), pC->GetParaAttribs() ); 1355 else 1356 { 1357 SfxItemSet aAttribs( GetEmptyItemSet() ); 1358 ConvertAndPutItems( aAttribs, pC->GetParaAttribs(), &eSourceUnit, &eDestUnit ); 1359 SetParaAttribs( aEditDoc.GetPos( aPaM.GetNode() ), aAttribs ); 1360 } 1361 } 1362 if ( bNewContent && bUsePortionInfo ) 1363 { 1364 XParaPortion* pXP = pPortionInfo->GetObject( n ); 1365 DBG_ASSERT( pXP, "InsertBinTextObject: PortionInfo?" ); 1366 ParaPortion* pParaPortion = GetParaPortions()[ nPara ]; 1367 DBG_ASSERT( pParaPortion, "InsertBinTextObject: ParaPortion?" ); 1368 pParaPortion->nHeight = pXP->nHeight; 1369 pParaPortion->nFirstLineOffset = pXP->nFirstLineOffset; 1370 pParaPortion->bForceRepaint = sal_True; 1371 pParaPortion->SetValid(); // Nicht formatieren 1372 1373 // Die TextPortions 1374 pParaPortion->GetTextPortions().Reset(); 1375 sal_uInt16 nCount = pXP->aTextPortions.Count(); 1376 for ( sal_uInt16 _n = 0; _n < nCount; _n++ ) 1377 { 1378 TextPortion* pTextPortion = pXP->aTextPortions[_n]; 1379 TextPortion* pNew = new TextPortion( *pTextPortion ); 1380 pParaPortion->GetTextPortions().Insert( pNew, _n ); 1381 } 1382 1383 // Die Zeilen 1384 pParaPortion->GetLines().Reset(); 1385 nCount = pXP->aLines.Count(); 1386 for ( sal_uInt16 m = 0; m < nCount; m++ ) 1387 { 1388 EditLine* pLine = pXP->aLines[m]; 1389 EditLine* pNew = pLine->Clone(); 1390 pNew->SetInvalid(); // neu Painten! 1391 pParaPortion->GetLines().Insert( pNew, m ); 1392 } 1393 #ifdef DBG_UTIL 1394 sal_uInt16 nTest; 1395 int nTPLen = 0, nTxtLen = 0; 1396 for ( nTest = pParaPortion->GetTextPortions().Count(); nTest; ) 1397 nTPLen += pParaPortion->GetTextPortions().GetObject( --nTest )->GetLen(); 1398 for ( nTest = pParaPortion->GetLines().Count(); nTest; ) 1399 nTxtLen += pParaPortion->GetLines().GetObject( --nTest )->GetLen(); 1400 DBG_ASSERT( ( nTPLen == pParaPortion->GetNode()->Len() ) && ( nTxtLen == pParaPortion->GetNode()->Len() ), "InsertBinTextObject: ParaPortion not completely formatted!" ); 1401 #endif 1402 } 1403 } 1404 if ( !bParaAttribs ) // DefFont wird bei FastInsertParagraph nicht berechnet 1405 { 1406 aPaM.GetNode()->GetCharAttribs().GetDefFont() = aEditDoc.GetDefFont(); 1407 if ( aStatus.UseCharAttribs() ) 1408 aPaM.GetNode()->CreateDefFont(); 1409 } 1410 1411 #ifndef SVX_LIGHT 1412 if ( bNewContent && GetStatus().DoOnlineSpelling() && pC->GetWrongList() ) 1413 { 1414 aPaM.GetNode()->DestroyWrongList(); // otherwise MLK, if list exists... 1415 aPaM.GetNode()->SetWrongList( pC->GetWrongList()->Clone() ); 1416 } 1417 #endif // !SVX_LIGHT 1418 1419 // Zeilenumbruch, wenn weitere folgen... 1420 if ( n < ( nContents-1) ) 1421 { 1422 if ( bNewContent ) 1423 aPaM = ImpFastInsertParagraph( nPara+1 ); 1424 else 1425 aPaM = ImpInsertParaBreak( aPaM, sal_False ); 1426 } 1427 } 1428 1429 aSel.Max() = aPaM; 1430 DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "InsertBibTextObject: Selektion kaput!(1)" ); 1431 return aSel; 1432 } 1433 1434 LanguageType ImpEditEngine::GetLanguage( const EditPaM& rPaM, sal_uInt16* pEndPos ) const 1435 { 1436 short nScriptType = GetScriptType( rPaM, pEndPos ); // pEndPos will be valid now, pointing to ScriptChange or NodeLen 1437 sal_uInt16 nLangId = GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ); 1438 const SvxLanguageItem* pLangItem = &(const SvxLanguageItem&)rPaM.GetNode()->GetContentAttribs().GetItem( nLangId ); 1439 EditCharAttrib* pAttr = rPaM.GetNode()->GetCharAttribs().FindAttrib( nLangId, rPaM.GetIndex() ); 1440 if ( pAttr ) 1441 pLangItem = (const SvxLanguageItem*)pAttr->GetItem(); 1442 1443 if ( pEndPos && pAttr && ( pAttr->GetEnd() < *pEndPos ) ) 1444 *pEndPos = pAttr->GetEnd(); 1445 1446 return pLangItem->GetLanguage(); 1447 } 1448 1449 ::com::sun::star::lang::Locale ImpEditEngine::GetLocale( const EditPaM& rPaM ) const 1450 { 1451 return SvxCreateLocale( GetLanguage( rPaM ) ); 1452 } 1453 1454 Reference< XSpellChecker1 > ImpEditEngine::GetSpeller() 1455 { 1456 #ifndef SVX_LIGHT 1457 if ( !xSpeller.is() ) 1458 xSpeller = SvxGetSpellChecker(); 1459 #endif 1460 return xSpeller; 1461 } 1462 1463 1464 SpellInfo * ImpEditEngine::CreateSpellInfo( const EditSelection &rSel, bool bMultipleDocs ) 1465 { 1466 if (!pSpellInfo) 1467 pSpellInfo = new SpellInfo; 1468 else 1469 *pSpellInfo = SpellInfo(); // reset to default values 1470 1471 pSpellInfo->bMultipleDoc = bMultipleDocs; 1472 EditSelection aSentenceSel( SelectSentence( rSel ) ); 1473 // pSpellInfo->aSpellStart = CreateEPaM( aSentenceSel.Min() ); 1474 // pSpellInfo->aSpellTo = CreateEPaM( rSel.HasRange()? aSentenceSel.Max() : aSentenceSel.Min() ); 1475 // always spell draw objects completely, startting at the top. 1476 // (spelling in only a selection or not starting with the top requires 1477 // further changes elsewehe to work properly) 1478 pSpellInfo->aSpellStart = EPaM(); 1479 pSpellInfo->aSpellTo = EPaM( EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND ); 1480 return pSpellInfo; 1481 } 1482 1483 1484 EESpellState ImpEditEngine::Spell( EditView* pEditView, sal_Bool bMultipleDoc ) 1485 { 1486 #ifdef SVX_LIGHT 1487 return EE_SPELL_NOSPELLER; 1488 #else 1489 1490 DBG_ASSERTWARNING( xSpeller.is(), "Kein Speller gesetzt!" ); 1491 1492 if ( !xSpeller.is() ) 1493 return EE_SPELL_NOSPELLER; 1494 1495 aOnlineSpellTimer.Stop(); 1496 1497 // Bei MultipleDoc immer von vorne/hinten... 1498 if ( bMultipleDoc ) 1499 { 1500 pEditView->pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); 1501 } 1502 1503 EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); 1504 pSpellInfo = CreateSpellInfo( aCurSel, bMultipleDoc ); 1505 1506 sal_Bool bIsStart = sal_False; 1507 if ( bMultipleDoc ) 1508 bIsStart = sal_True; // Immer von Vorne bzw. von hinten... 1509 else if ( ( CreateEPaM( aEditDoc.GetStartPaM() ) == pSpellInfo->aSpellStart ) ) 1510 bIsStart = sal_True; 1511 1512 EditSpellWrapper* pWrp = new EditSpellWrapper( Application::GetDefDialogParent(), 1513 xSpeller, bIsStart, sal_False, pEditView ); 1514 pWrp->SpellDocument(); 1515 delete pWrp; 1516 1517 if ( !bMultipleDoc ) 1518 { 1519 pEditView->pImpEditView->DrawSelection(); 1520 if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() ) 1521 aCurSel.Max().GetIndex() = aCurSel.Max().GetNode()->Len(); 1522 aCurSel.Min() = aCurSel.Max(); 1523 pEditView->pImpEditView->SetEditSelection( aCurSel ); 1524 pEditView->pImpEditView->DrawSelection(); 1525 pEditView->ShowCursor( sal_True, sal_False ); 1526 } 1527 EESpellState eState = pSpellInfo->eState; 1528 delete pSpellInfo; 1529 pSpellInfo = 0; 1530 return eState; 1531 #endif 1532 } 1533 1534 1535 sal_Bool ImpEditEngine::HasConvertibleTextPortion( LanguageType nSrcLang ) 1536 { 1537 #ifdef SVX_LIGHT 1538 return sal_False; 1539 #else 1540 sal_Bool bHasConvTxt = sal_False; 1541 1542 sal_uInt16 nParas = pEditEngine->GetParagraphCount(); 1543 for (sal_uInt16 k = 0; k < nParas; ++k) 1544 { 1545 SvUShorts aPortions; 1546 pEditEngine->GetPortions( k, aPortions ); 1547 for ( sal_uInt16 nPos = 0; nPos < aPortions.Count(); ++nPos ) 1548 { 1549 sal_uInt16 nEnd = aPortions.GetObject( nPos ); 1550 sal_uInt16 nStart = nPos > 0 ? aPortions.GetObject( nPos - 1 ) : 0; 1551 1552 // if the paragraph is not empty we need to increase the index 1553 // by one since the attribute of the character left to the 1554 // specified position is evaluated. 1555 if (nEnd > nStart) // empty para? 1556 ++nStart; 1557 LanguageType nLangFound = pEditEngine->GetLanguage( k, nStart ); 1558 #ifdef DEBUG 1559 lang::Locale aLocale( SvxCreateLocale( nLangFound ) ); 1560 #endif 1561 bHasConvTxt = (nSrcLang == nLangFound) || 1562 (editeng::HangulHanjaConversion::IsChinese( nLangFound ) && 1563 editeng::HangulHanjaConversion::IsChinese( nSrcLang )); 1564 if (bHasConvTxt) 1565 return bHasConvTxt; 1566 } 1567 } 1568 1569 #endif 1570 return bHasConvTxt; 1571 } 1572 1573 1574 void ImpEditEngine::Convert( EditView* pEditView, 1575 LanguageType nSrcLang, LanguageType nDestLang, const Font *pDestFont, 1576 sal_Int32 nOptions, sal_Bool bIsInteractive, sal_Bool bMultipleDoc ) 1577 { 1578 // modified version of ImpEditEngine::Spell 1579 1580 #ifdef SVX_LIGHT 1581 #else 1582 1583 // Bei MultipleDoc immer von vorne/hinten... 1584 if ( bMultipleDoc ) 1585 pEditView->pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); 1586 1587 // 1588 // initialize pConvInfo 1589 // 1590 EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); 1591 aCurSel.Adjust( aEditDoc ); 1592 pConvInfo = new ConvInfo; 1593 pConvInfo->bMultipleDoc = bMultipleDoc; 1594 pConvInfo->aConvStart = CreateEPaM( aCurSel.Min() ); 1595 // 1596 // if it is not just a selection and we are about to begin 1597 // with the current conversion for the very first time 1598 // we need to find the start of the current (initial) 1599 // convertible unit in order for the text conversion to give 1600 // the correct result for that. Since it is easier to obtain 1601 // the start of the word we use that though. 1602 if (!aCurSel.HasRange() && ImplGetBreakIterator().is()) 1603 { 1604 EditPaM aWordStartPaM( SelectWord( aCurSel, i18n::WordType::DICTIONARY_WORD ).Min() ); 1605 1606 // since #118246 / #117803 still occurs if the cursor is placed 1607 // between the two chinese characters to be converted (because both 1608 // of them are words on their own!) using the word boundary here does 1609 // not work. Thus since chinese conversion is not interactive we start 1610 // at the begin of the paragraph to solve the problem, i.e. have the 1611 // TextConversion service get those characters together in the same call. 1612 sal_uInt16 nStartIdx = ( editeng::HangulHanjaConversion::IsChinese( nSrcLang ) ) ? 1613 0 : aWordStartPaM.GetIndex(); 1614 pConvInfo->aConvStart.nIndex = nStartIdx; 1615 } 1616 // 1617 pConvInfo->aConvContinue = pConvInfo->aConvStart; 1618 1619 sal_Bool bIsStart = sal_False; 1620 if ( bMultipleDoc ) 1621 bIsStart = sal_True; // Immer von Vorne bzw. von hinten... 1622 else if ( CreateEPaM( aEditDoc.GetStartPaM() ) == pConvInfo->aConvStart ) 1623 bIsStart = sal_True; 1624 1625 bImpConvertFirstCall = sal_True; // next ImpConvert call is the very first in this conversion turn 1626 1627 Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); 1628 TextConvWrapper aWrp( Application::GetDefDialogParent(), xMSF, 1629 SvxCreateLocale( nSrcLang ), SvxCreateLocale( nDestLang ), 1630 pDestFont, 1631 nOptions, bIsInteractive, 1632 bIsStart, pEditView ); 1633 1634 // 1635 //!! optimization does not work since when update mode is false 1636 //!! the object is 'lying' about it portions, paragraphs, 1637 //!! EndPaM... later on. 1638 //!! Should not be a great problem since text boxes or cells in 1639 //!! Calc usually have only a rather short text. 1640 // 1641 // disallow formatting, updating the view, ... while 1642 // non-interactively converting the document. (saves time) 1643 //if (!bIsInteractive) 1644 // SetUpdateMode( sal_False ); 1645 1646 aWrp.Convert(); 1647 1648 //if (!bIsInteractive) 1649 //SetUpdateMode( sal_True, 0, sal_True ); 1650 1651 if ( !bMultipleDoc ) 1652 { 1653 pEditView->pImpEditView->DrawSelection(); 1654 if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() ) 1655 aCurSel.Max().GetIndex() = aCurSel.Max().GetNode()->Len(); 1656 aCurSel.Min() = aCurSel.Max(); 1657 pEditView->pImpEditView->SetEditSelection( aCurSel ); 1658 pEditView->pImpEditView->DrawSelection(); 1659 pEditView->ShowCursor( sal_True, sal_False ); 1660 } 1661 delete pConvInfo; 1662 pConvInfo = 0; 1663 #endif 1664 } 1665 1666 1667 void ImpEditEngine::SetLanguageAndFont( 1668 const ESelection &rESel, 1669 LanguageType nLang, sal_uInt16 nLangWhichId, 1670 const Font *pFont, sal_uInt16 nFontWhichId ) 1671 { 1672 ESelection aOldSel = pActiveView->GetSelection(); 1673 pActiveView->SetSelection( rESel ); 1674 1675 // set new language attribute 1676 SfxItemSet aNewSet( pActiveView->GetEmptyItemSet() ); 1677 aNewSet.Put( SvxLanguageItem( nLang, nLangWhichId ) ); 1678 1679 // new font to be set? 1680 DBG_ASSERT( pFont, "target font missing?" ); 1681 if (pFont) 1682 { 1683 // set new font attribute 1684 SvxFontItem aFontItem = (SvxFontItem&) aNewSet.Get( nFontWhichId ); 1685 aFontItem.SetFamilyName( pFont->GetName()); 1686 aFontItem.SetFamily( pFont->GetFamily()); 1687 aFontItem.SetStyleName( pFont->GetStyleName()); 1688 aFontItem.SetPitch( pFont->GetPitch()); 1689 aFontItem.SetCharSet( pFont->GetCharSet() ); 1690 aNewSet.Put( aFontItem ); 1691 } 1692 1693 // apply new attributes 1694 pActiveView->SetAttribs( aNewSet ); 1695 1696 pActiveView->SetSelection( aOldSel ); 1697 } 1698 1699 1700 void ImpEditEngine::ImpConvert( rtl::OUString &rConvTxt, LanguageType &rConvTxtLang, 1701 EditView* pEditView, LanguageType nSrcLang, const ESelection &rConvRange, 1702 sal_Bool bAllowImplicitChangesForNotConvertibleText, 1703 LanguageType nTargetLang, const Font *pTargetFont ) 1704 { 1705 // modified version of ImpEditEngine::ImpSpell 1706 1707 // looks for next convertible text portion to be passed on to the wrapper 1708 1709 String aRes; 1710 LanguageType nResLang = LANGUAGE_NONE; 1711 1712 #ifdef SVX_LIGHT 1713 rConvTxt = rtl::OUString(); 1714 rConvTxtLang = LANGUAGE_NONE; 1715 #else 1716 1717 /* ContentNode* pLastNode = */ aEditDoc.SaveGetObject( aEditDoc.Count()-1 ); 1718 1719 EditPaM aPos( CreateEditPaM( pConvInfo->aConvContinue ) ); 1720 EditSelection aCurSel = EditSelection( aPos, aPos ); 1721 1722 String aWord; 1723 1724 while (!aRes.Len()) 1725 { 1726 // empty paragraph found that needs to have language and font set? 1727 if (bAllowImplicitChangesForNotConvertibleText && 1728 !pEditEngine->GetText( pConvInfo->aConvContinue.nPara ).Len()) 1729 { 1730 sal_uInt16 nPara = pConvInfo->aConvContinue.nPara; 1731 ESelection aESel( nPara, 0, nPara, 0 ); 1732 // see comment for below same function call 1733 SetLanguageAndFont( aESel, 1734 nTargetLang, EE_CHAR_LANGUAGE_CJK, 1735 pTargetFont, EE_CHAR_FONTINFO_CJK ); 1736 } 1737 1738 1739 if (pConvInfo->aConvContinue.nPara == pConvInfo->aConvTo.nPara && 1740 pConvInfo->aConvContinue.nIndex >= pConvInfo->aConvTo.nIndex) 1741 break; 1742 1743 /* 1744 // Bekannter (wahrscheinlicher) Bug: Wenn SpellToCurrent, muss 1745 // Current bei jeder Ersetzung korrigiert werden, sonst passt 1746 // das Ende evtl. nicht mehr genau... 1747 if ( pConvInfo->bConvToEnd || pConvInfo->bMultipleDoc ) 1748 { 1749 if ( aCurSel.Max().GetNode() == pLastNode && 1750 aCurSel.Max().GetIndex() >= pLastNode->Len() ) 1751 break; 1752 } 1753 */ 1754 1755 sal_uInt16 nAttribStart = USHRT_MAX; 1756 sal_uInt16 nAttribEnd = USHRT_MAX; 1757 sal_uInt16 nCurPos = USHRT_MAX; 1758 EPaM aCurStart = CreateEPaM( aCurSel.Min() ); 1759 SvUShorts aPortions; 1760 pEditEngine->GetPortions( (sal_uInt16)aCurStart.nPara, aPortions ); 1761 for ( sal_uInt16 nPos = 0; nPos < aPortions.Count(); ++nPos ) 1762 { 1763 sal_uInt16 nEnd = aPortions.GetObject( nPos ); 1764 sal_uInt16 nStart = nPos > 0 ? aPortions.GetObject( nPos - 1 ) : 0; 1765 1766 // the language attribute is obtained from the left character 1767 // (like usually all other attributes) 1768 // thus we usually have to add 1 in order to get the language 1769 // of the text right to the cursor position 1770 sal_uInt16 nLangIdx = nEnd > nStart ? nStart + 1 : nStart; 1771 LanguageType nLangFound = pEditEngine->GetLanguage( aCurStart.nPara, nLangIdx ); 1772 #ifdef DEBUG 1773 lang::Locale aLocale( SvxCreateLocale( nLangFound ) ); 1774 #endif 1775 sal_Bool bLangOk = (nLangFound == nSrcLang) || 1776 (editeng::HangulHanjaConversion::IsChinese( nLangFound ) && 1777 editeng::HangulHanjaConversion::IsChinese( nSrcLang )); 1778 1779 if (nAttribEnd != USHRT_MAX) // start already found? 1780 { 1781 DBG_ASSERT(nEnd >= aCurStart.nIndex, "error while scanning attributes (a)" ); 1782 DBG_ASSERT(nEnd >= nAttribEnd, "error while scanning attributes (b)" ); 1783 if (/*nEnd >= aCurStart.nIndex &&*/ nLangFound == nResLang) 1784 nAttribEnd = nEnd; 1785 else // language attrib has changed 1786 break; 1787 } 1788 if (nAttribStart == USHRT_MAX && // start not yet found? 1789 nEnd > aCurStart.nIndex && bLangOk) 1790 { 1791 nAttribStart = nStart; 1792 nAttribEnd = nEnd; 1793 nResLang = nLangFound; 1794 } 1795 //! the list of portions may have changed compared to the previous 1796 //! call to this function (because of possibly changed language 1797 //! attribute!) 1798 //! But since we don't want to start in the already processed part 1799 //! we clip the start accordingly. 1800 if (nAttribStart < aCurStart.nIndex) 1801 { 1802 nAttribStart = aCurStart.nIndex; 1803 } 1804 1805 // check script type to the right of the start of the current portion 1806 EditPaM aPaM( CreateEditPaM( EPaM(aCurStart.nPara, nLangIdx) ) ); 1807 sal_Bool bIsAsianScript = (i18n::ScriptType::ASIAN == GetScriptType( aPaM )); 1808 // not yet processed text part with for conversion 1809 // not suitable language found that needs to be changed? 1810 if (bAllowImplicitChangesForNotConvertibleText && 1811 !bLangOk && !bIsAsianScript && nEnd > aCurStart.nIndex) 1812 { 1813 ESelection aESel( aCurStart.nPara, nStart, aCurStart.nPara, nEnd ); 1814 // set language and font to target language and font of conversion 1815 //! Now this especially includes all non convertible text e.g. 1816 //! spaces, empty paragraphs and western text. 1817 // This is in order for every *new* text entered at *any* position to 1818 // have the correct language and font attributes set. 1819 SetLanguageAndFont( aESel, 1820 nTargetLang, EE_CHAR_LANGUAGE_CJK, 1821 pTargetFont, EE_CHAR_FONTINFO_CJK ); 1822 } 1823 1824 nCurPos = nEnd; 1825 } 1826 1827 if (nAttribStart != USHRT_MAX && nAttribEnd != USHRT_MAX) 1828 { 1829 aCurSel.Min().SetIndex( nAttribStart ); 1830 aCurSel.Max().SetIndex( nAttribEnd ); 1831 } 1832 else if (nCurPos != USHRT_MAX) 1833 { 1834 // set selection to end of scanned text 1835 // (used to set the position where to continue from later on) 1836 aCurSel.Min().SetIndex( nCurPos ); 1837 aCurSel.Max().SetIndex( nCurPos ); 1838 } 1839 1840 if ( !pConvInfo->bConvToEnd ) 1841 { 1842 EPaM aEPaM( CreateEPaM( aCurSel.Min() ) ); 1843 if ( !( aEPaM < pConvInfo->aConvTo ) ) 1844 break; 1845 } 1846 1847 // clip selected word to the converted area 1848 // (main use when conversion starts/ends **within** a word) 1849 EditPaM aPaM( CreateEditPaM( pConvInfo->aConvStart ) ); 1850 if (pConvInfo->bConvToEnd && 1851 aCurSel.Min().GetNode() == aPaM.GetNode() && 1852 aCurSel.Min().GetIndex() < aPaM.GetIndex()) 1853 aCurSel.Min().SetIndex( aPaM.GetIndex() ); 1854 aPaM = CreateEditPaM( pConvInfo->aConvContinue ); 1855 if (aCurSel.Min().GetNode() == aPaM.GetNode() && 1856 aCurSel.Min().GetIndex() < aPaM.GetIndex()) 1857 aCurSel.Min().SetIndex( aPaM.GetIndex() ); 1858 aPaM = CreateEditPaM( pConvInfo->aConvTo ); 1859 if ((!pConvInfo->bConvToEnd || rConvRange.HasRange())&& 1860 aCurSel.Max().GetNode() == aPaM.GetNode() && 1861 aCurSel.Max().GetIndex() > aPaM.GetIndex()) 1862 aCurSel.Max().SetIndex( aPaM.GetIndex() ); 1863 1864 aWord = GetSelected( aCurSel ); 1865 1866 if ( aWord.Len() > 0 /* && bLangOk */) 1867 aRes = aWord; 1868 1869 // move to next word/paragraph if necessary 1870 if ( !aRes.Len() ) 1871 aCurSel = WordRight( aCurSel.Min(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 1872 1873 pConvInfo->aConvContinue = CreateEPaM( aCurSel.Max() ); 1874 } 1875 1876 pEditView->pImpEditView->DrawSelection(); 1877 pEditView->pImpEditView->SetEditSelection( aCurSel ); 1878 pEditView->pImpEditView->DrawSelection(); 1879 pEditView->ShowCursor( sal_True, sal_False ); 1880 1881 rConvTxt = aRes; 1882 if (rConvTxt.getLength()) 1883 rConvTxtLang = nResLang; 1884 #endif 1885 } 1886 1887 1888 Reference< XSpellAlternatives > ImpEditEngine::ImpSpell( EditView* pEditView ) 1889 { 1890 #ifdef SVX_LIGHT 1891 return Reference< XSpellAlternatives >(); 1892 #else 1893 1894 DBG_ASSERT( xSpeller.is(), "Kein Speller gesetzt!" ); 1895 1896 ContentNode* pLastNode = aEditDoc.SaveGetObject( (aEditDoc.Count()-1) ); 1897 EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); 1898 aCurSel.Min() = aCurSel.Max(); 1899 1900 String aWord; 1901 Reference< XSpellAlternatives > xSpellAlt; 1902 Sequence< PropertyValue > aEmptySeq; 1903 while (!xSpellAlt.is()) 1904 { 1905 1906 // Bekannter (wahrscheinlicher) Bug: Wenn SpellToCurrent, muss 1907 // Current bei jeder Ersetzung korrigiert werden, sonst passt 1908 // das Ende evtl. nicht mehr genau... 1909 if ( pSpellInfo->bSpellToEnd || pSpellInfo->bMultipleDoc ) 1910 { 1911 if ( aCurSel.Max().GetNode() == pLastNode ) 1912 { 1913 if ( ( aCurSel.Max().GetIndex() >= pLastNode->Len() ) ) 1914 break; 1915 } 1916 } 1917 else if ( !pSpellInfo->bSpellToEnd ) 1918 { 1919 EPaM aEPaM( CreateEPaM( aCurSel.Max() ) ); 1920 if ( !( aEPaM < pSpellInfo->aSpellTo ) ) 1921 break; 1922 } 1923 1924 aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 1925 aWord = GetSelected( aCurSel ); 1926 1927 // Wenn Punkt dahinter, muss dieser mit uebergeben werden ! 1928 // Falls Abkuerzung... 1929 if ( aWord.Len() && ( aCurSel.Max().GetIndex() < aCurSel.Max().GetNode()->Len() ) ) 1930 { 1931 sal_Unicode cNext = aCurSel.Max().GetNode()->GetChar( aCurSel.Max().GetIndex() ); 1932 if ( cNext == '.' ) 1933 { 1934 aCurSel.Max().GetIndex()++; 1935 aWord += cNext; 1936 } 1937 } 1938 1939 if ( aWord.Len() > 0 ) 1940 { 1941 LanguageType eLang = GetLanguage( aCurSel.Max() ); 1942 SvxSpellWrapper::CheckSpellLang( xSpeller, eLang ); 1943 xSpellAlt = xSpeller->spell( aWord, eLang, aEmptySeq ); 1944 } 1945 1946 if ( !xSpellAlt.is() ) 1947 aCurSel = WordRight( aCurSel.Min(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 1948 else 1949 pSpellInfo->eState = EE_SPELL_ERRORFOUND; 1950 } 1951 1952 pEditView->pImpEditView->DrawSelection(); 1953 pEditView->pImpEditView->SetEditSelection( aCurSel ); 1954 pEditView->pImpEditView->DrawSelection(); 1955 pEditView->ShowCursor( sal_True, sal_False ); 1956 return xSpellAlt; 1957 #endif 1958 } 1959 /*-- 13.10.2003 16:43:27--------------------------------------------------- 1960 1961 -----------------------------------------------------------------------*/ 1962 void ImpEditEngine::EndSpelling() 1963 { 1964 DELETEZ(pSpellInfo); 1965 } 1966 /*-- 13.10.2003 16:43:27--------------------------------------------------- 1967 1968 -----------------------------------------------------------------------*/ 1969 void ImpEditEngine::StartSpelling(EditView& rEditView, sal_Bool bMultipleDoc) 1970 { 1971 DBG_ASSERT(!pSpellInfo, "pSpellInfo already set?"); 1972 rEditView.pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); 1973 EditSelection aCurSel( rEditView.pImpEditView->GetEditSelection() ); 1974 pSpellInfo = CreateSpellInfo( aCurSel, bMultipleDoc ); 1975 } 1976 /*-- 13.10.2003 16:43:27--------------------------------------------------- 1977 Search for the next wrong word within the given selection 1978 -----------------------------------------------------------------------*/ 1979 Reference< XSpellAlternatives > ImpEditEngine::ImpFindNextError(EditSelection& rSelection) 1980 { 1981 /* ContentNode* pLastNode = */ aEditDoc.SaveGetObject( (aEditDoc.Count()-1) ); 1982 EditSelection aCurSel( rSelection.Min() ); 1983 1984 String aWord; 1985 Reference< XSpellAlternatives > xSpellAlt; 1986 Sequence< PropertyValue > aEmptySeq; 1987 while (!xSpellAlt.is()) 1988 { 1989 //check if the end of the selection has been reached 1990 { 1991 EPaM aEPaM( CreateEPaM( aCurSel.Max() ) ); 1992 if ( !( aEPaM < CreateEPaM( rSelection.Max()) ) ) 1993 break; 1994 } 1995 1996 aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 1997 aWord = GetSelected( aCurSel ); 1998 1999 // Wenn Punkt dahinter, muss dieser mit uebergeben werden ! 2000 // Falls Abkuerzung... 2001 if ( aWord.Len() && ( aCurSel.Max().GetIndex() < aCurSel.Max().GetNode()->Len() ) ) 2002 { 2003 sal_Unicode cNext = aCurSel.Max().GetNode()->GetChar( aCurSel.Max().GetIndex() ); 2004 if ( cNext == '.' ) 2005 { 2006 aCurSel.Max().GetIndex()++; 2007 aWord += cNext; 2008 } 2009 } 2010 2011 if ( aWord.Len() > 0 ) 2012 xSpellAlt = xSpeller->spell( aWord, GetLanguage( aCurSel.Max() ), aEmptySeq ); 2013 2014 if ( !xSpellAlt.is() ) 2015 aCurSel = WordRight( aCurSel.Min(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 2016 else 2017 { 2018 pSpellInfo->eState = EE_SPELL_ERRORFOUND; 2019 rSelection = aCurSel; 2020 } 2021 } 2022 return xSpellAlt; 2023 } 2024 /*-- 13.10.2003 16:43:27--------------------------------------------------- 2025 2026 -----------------------------------------------------------------------*/ 2027 bool ImpEditEngine::SpellSentence(EditView& rEditView, 2028 ::svx::SpellPortions& rToFill, 2029 bool /*bIsGrammarChecking*/ ) 2030 { 2031 #ifdef SVX_LIGHT 2032 #else 2033 bool bRet = false; 2034 EditSelection aCurSel( rEditView.pImpEditView->GetEditSelection() ); 2035 if(!pSpellInfo) 2036 pSpellInfo = CreateSpellInfo( aCurSel, true ); 2037 pSpellInfo->aCurSentenceStart = aCurSel.Min(); 2038 DBG_ASSERT( xSpeller.is(), "Kein Speller gesetzt!" ); 2039 pSpellInfo->aLastSpellPortions.clear(); 2040 pSpellInfo->aLastSpellContentSelections.clear(); 2041 rToFill.clear(); 2042 //if no selection previously exists the range is extended to the end of the object 2043 if(aCurSel.Min() == aCurSel.Max()) 2044 { 2045 ContentNode* pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count()-1); 2046 aCurSel.Max() = EditPaM(pLastNode, pLastNode->Len()); 2047 } 2048 // check for next error in aCurSel and set aCurSel to that one if any was found 2049 Reference< XSpellAlternatives > xAlt = ImpFindNextError(aCurSel); 2050 if (xAlt.is()) 2051 { 2052 bRet = true; 2053 //find the sentence boundaries 2054 EditSelection aSentencePaM = SelectSentence(aCurSel); 2055 //make sure that the sentence is never smaller than the error range! 2056 if(aSentencePaM.Max().GetIndex() < aCurSel.Max().GetIndex()) 2057 aSentencePaM.Max() = aCurSel.Max(); 2058 //add the portion preceeding the error 2059 EditSelection aStartSelection(aSentencePaM.Min(), aCurSel.Min()); 2060 if(aStartSelection.HasRange()) 2061 AddPortionIterated(rEditView, aStartSelection, 0, rToFill); 2062 //add the error portion 2063 AddPortionIterated(rEditView, aCurSel, xAlt, rToFill); 2064 //find the end of the sentence 2065 //search for all errors in the rest of the sentence and add all the portions 2066 do 2067 { 2068 EditSelection aNextSel = EditSelection(aCurSel.Max(), aSentencePaM.Max()); 2069 xAlt = ImpFindNextError(aNextSel); 2070 if(xAlt.is()) 2071 { 2072 //add the part between the previous and the current error 2073 AddPortionIterated(rEditView, EditSelection(aCurSel.Max(), aNextSel.Min()), 0, rToFill); 2074 //add the current error 2075 AddPortionIterated(rEditView, aNextSel, xAlt, rToFill); 2076 } 2077 else 2078 AddPortionIterated(rEditView, EditSelection(aCurSel.Max(), aSentencePaM.Max()), xAlt, rToFill); 2079 aCurSel = aNextSel; 2080 } 2081 while( xAlt.is() ); 2082 2083 //set the selection to the end of the current sentence 2084 rEditView.pImpEditView->SetEditSelection(aSentencePaM.Max()); 2085 } 2086 #endif 2087 return bRet; 2088 } 2089 2090 /*-- 15.10.2003 16:09:12--------------------------------------------------- 2091 adds one portion to the SpellPortions 2092 -----------------------------------------------------------------------*/ 2093 void ImpEditEngine::AddPortion( 2094 const EditSelection rSel, 2095 uno::Reference< XSpellAlternatives > xAlt, 2096 ::svx::SpellPortions& rToFill, 2097 bool bIsField) 2098 { 2099 #ifdef SVX_LIGHT 2100 #else 2101 if(rSel.HasRange()) 2102 { 2103 svx::SpellPortion aPortion; 2104 aPortion.sText = GetSelected( rSel ); 2105 aPortion.eLanguage = GetLanguage( rSel.Min() ); 2106 aPortion.xAlternatives = xAlt; 2107 aPortion.bIsField = bIsField; 2108 rToFill.push_back(aPortion); 2109 2110 //save the spelled portions for later use 2111 pSpellInfo->aLastSpellPortions.push_back(aPortion); 2112 pSpellInfo->aLastSpellContentSelections.push_back(rSel); 2113 2114 } 2115 #endif 2116 } 2117 2118 /*-- 15.10.2003 16:07:47--------------------------------------------------- 2119 adds one or more portions of text to the SpellPortions depending on language changes 2120 -----------------------------------------------------------------------*/ 2121 void ImpEditEngine::AddPortionIterated( 2122 EditView& rEditView, 2123 const EditSelection rSel, 2124 Reference< XSpellAlternatives > xAlt, 2125 ::svx::SpellPortions& rToFill) 2126 { 2127 #ifdef SVX_LIGHT 2128 #else 2129 if(rSel.Min() != rSel.Max()) 2130 { 2131 if(xAlt.is()) 2132 { 2133 AddPortion(rSel, xAlt, rToFill, false); 2134 } 2135 else 2136 { 2137 //iterate and search for language attribute changes 2138 //save the start and end positions 2139 bool bTest = rSel.Min().GetIndex() <= rSel.Max().GetIndex(); 2140 EditPaM aStart(bTest ? rSel.Min() : rSel.Max()); 2141 EditPaM aEnd(bTest ? rSel.Max() : rSel.Min()); 2142 //iterate over the text to find changes in language 2143 //set the mark equal to the point 2144 EditPaM aCursor(aStart); 2145 rEditView.pImpEditView->SetEditSelection( aCursor ); 2146 LanguageType eStartLanguage = GetLanguage( aCursor ); 2147 //search for a field attribute at the beginning - only the end position 2148 //of this field is kept to end a portion at that position 2149 const EditCharAttrib* pFieldAttr = aCursor.GetNode()->GetCharAttribs(). 2150 FindFeature( aCursor.GetIndex() ); 2151 bool bIsField = pFieldAttr && 2152 pFieldAttr->GetStart() == aCursor.GetIndex() && 2153 pFieldAttr->GetStart() != pFieldAttr->GetEnd() && 2154 pFieldAttr->Which() == EE_FEATURE_FIELD; 2155 sal_uInt16 nEndField = bIsField ? pFieldAttr->GetEnd() : USHRT_MAX; 2156 bool bIsEndField = false; 2157 do 2158 { 2159 aCursor = CursorRight( aCursor); 2160 //determine whether a field and has been reached 2161 bIsEndField = nEndField == aCursor.GetIndex(); 2162 //search for a new field attribute 2163 EditCharAttrib* _pFieldAttr = aCursor.GetNode()->GetCharAttribs(). 2164 FindFeature( aCursor.GetIndex() ); 2165 bIsField = _pFieldAttr && 2166 _pFieldAttr->GetStart() == aCursor.GetIndex() && 2167 _pFieldAttr->GetStart() != _pFieldAttr->GetEnd() && 2168 _pFieldAttr->Which() == EE_FEATURE_FIELD; 2169 //on every new field move the end position 2170 if(bIsField) 2171 nEndField = bIsField ? _pFieldAttr->GetEnd() : USHRT_MAX; 2172 2173 LanguageType eCurLanguage = GetLanguage( aCursor ); 2174 if(eCurLanguage != eStartLanguage || bIsField || bIsEndField) 2175 { 2176 eStartLanguage = eCurLanguage; 2177 //go one step back - the cursor currently selects the first character 2178 //with a different language 2179 //create a selection from start to the current Cursor 2180 EditSelection aSelection(aStart, aCursor); 2181 AddPortion(aSelection, xAlt, rToFill, bIsEndField); 2182 aStart = aCursor; 2183 } 2184 } 2185 while(aCursor.GetIndex() < aEnd.GetIndex()); 2186 EditSelection aSelection(aStart, aCursor); 2187 AddPortion(aSelection, xAlt, rToFill, bIsField); 2188 } 2189 } 2190 #endif 2191 } 2192 2193 /*-- 13.10.2003 16:43:33--------------------------------------------------- 2194 2195 -----------------------------------------------------------------------*/ 2196 void ImpEditEngine::ApplyChangedSentence(EditView& rEditView, 2197 const ::svx::SpellPortions& rNewPortions, 2198 bool bRecheck ) 2199 { 2200 #ifdef SVX_LIGHT 2201 #else 2202 // Note: rNewPortions.size() == 0 is valid and happens when the whole 2203 // sentence got removed in the dialog 2204 2205 DBG_ASSERT(pSpellInfo, "pSpellInfo not initialized"); 2206 if (pSpellInfo && 2207 pSpellInfo->aLastSpellPortions.size() > 0) // no portions -> no text to be changed 2208 { 2209 // get current paragraph length to calculate later on how the sentence length changed, 2210 // in order to place the cursor at the end of the sentence again 2211 EditSelection aOldSel( rEditView.pImpEditView->GetEditSelection() ); 2212 xub_StrLen nOldLen = aOldSel.Max().GetNode()->Len(); 2213 2214 UndoActionStart( EDITUNDO_INSERT ); 2215 if(pSpellInfo->aLastSpellPortions.size() == rNewPortions.size()) 2216 { 2217 DBG_ASSERT( rNewPortions.size() > 0, "rNewPortions should not be empty here" ); 2218 DBG_ASSERT( pSpellInfo->aLastSpellPortions.size() == pSpellInfo->aLastSpellContentSelections.size(), 2219 "aLastSpellPortions and aLastSpellContentSelections size mismatch" ); 2220 2221 //the simple case: the same number of elements on both sides 2222 //each changed element has to be applied to the corresponding source element 2223 svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.end(); 2224 svx::SpellPortions::const_iterator aCurrentOldPortion = pSpellInfo->aLastSpellPortions.end(); 2225 SpellContentSelections::const_iterator aCurrentOldPosition = pSpellInfo->aLastSpellContentSelections.end(); 2226 bool bSetToEnd = false; 2227 do 2228 { 2229 --aCurrentNewPortion; 2230 --aCurrentOldPortion; 2231 --aCurrentOldPosition; 2232 //set the cursor to the end of the sentence - necessary to 2233 //resume there at the next step 2234 if(!bSetToEnd) 2235 { 2236 bSetToEnd = true; 2237 rEditView.pImpEditView->SetEditSelection( aCurrentOldPosition->Max() ); 2238 } 2239 2240 sal_uInt16 nScriptType = GetI18NScriptTypeOfLanguage( aCurrentNewPortion->eLanguage ); 2241 // LanguageType eTextLanguage = GetLanguage( aCurrentOldPosition->Min() ); 2242 2243 sal_uInt16 nLangWhichId = EE_CHAR_LANGUAGE; 2244 switch(nScriptType) 2245 { 2246 case SCRIPTTYPE_ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break; 2247 case SCRIPTTYPE_COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break; 2248 } 2249 if(aCurrentNewPortion->sText != aCurrentOldPortion->sText) 2250 { 2251 //change text and apply language 2252 SfxItemSet aSet( aEditDoc.GetItemPool(), nLangWhichId, nLangWhichId); 2253 aSet.Put(SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId)); 2254 SetAttribs( *aCurrentOldPosition, aSet ); 2255 ImpInsertText( *aCurrentOldPosition, aCurrentNewPortion->sText ); 2256 } 2257 else if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage) 2258 { 2259 //apply language 2260 SfxItemSet aSet( aEditDoc.GetItemPool(), nLangWhichId, nLangWhichId); 2261 aSet.Put(SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId)); 2262 SetAttribs( *aCurrentOldPosition, aSet ); 2263 } 2264 if(aCurrentNewPortion == rNewPortions.begin()) 2265 break; 2266 } 2267 while(aCurrentNewPortion != rNewPortions.begin()); 2268 } 2269 else 2270 { 2271 DBG_ASSERT( pSpellInfo->aLastSpellContentSelections.size() > 0, "aLastSpellContentSelections should not be empty here" ); 2272 2273 //select the complete sentence 2274 SpellContentSelections::const_iterator aCurrentEndPosition = pSpellInfo->aLastSpellContentSelections.end(); 2275 --aCurrentEndPosition; 2276 SpellContentSelections::const_iterator aCurrentStartPosition = pSpellInfo->aLastSpellContentSelections.begin(); 2277 EditSelection aAllSentence(aCurrentStartPosition->Min(), aCurrentEndPosition->Max()); 2278 2279 //delete the sentence completely 2280 ImpDeleteSelection( aAllSentence ); 2281 svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.begin(); 2282 EditPaM aCurrentPaM = aAllSentence.Min(); 2283 while(aCurrentNewPortion != rNewPortions.end()) 2284 { 2285 //set the language attribute 2286 LanguageType eCurLanguage = GetLanguage( aCurrentPaM ); 2287 if(eCurLanguage != aCurrentNewPortion->eLanguage) 2288 { 2289 sal_uInt16 nScriptType = GetI18NScriptTypeOfLanguage( aCurrentNewPortion->eLanguage ); 2290 sal_uInt16 nLangWhichId = EE_CHAR_LANGUAGE; 2291 switch(nScriptType) 2292 { 2293 case SCRIPTTYPE_ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break; 2294 case SCRIPTTYPE_COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break; 2295 } 2296 SfxItemSet aSet( aEditDoc.GetItemPool(), nLangWhichId, nLangWhichId); 2297 aSet.Put(SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId)); 2298 SetAttribs( aCurrentPaM, aSet ); 2299 } 2300 //insert the new string and set the cursor to the end of the inserted string 2301 aCurrentPaM = ImpInsertText( aCurrentPaM , aCurrentNewPortion->sText ); 2302 ++aCurrentNewPortion; 2303 } 2304 } 2305 UndoActionEnd( EDITUNDO_INSERT ); 2306 2307 EditPaM aNext; 2308 if (bRecheck) 2309 aNext = pSpellInfo->aCurSentenceStart; 2310 else 2311 { 2312 // restore cursor position to the end of the modified sentence. 2313 // (This will define the continuation position for spell/grammar checking) 2314 // First: check if the sentence/para length changed 2315 sal_Int32 nDelta = rEditView.pImpEditView->GetEditSelection().Max().GetNode()->Len() - nOldLen; 2316 xub_StrLen nEndOfSentence = aOldSel.Max().GetIndex() + nDelta; 2317 aNext = EditPaM( aOldSel.Max().GetNode(), nEndOfSentence ); 2318 } 2319 rEditView.pImpEditView->SetEditSelection( aNext ); 2320 2321 FormatAndUpdate(); 2322 aEditDoc.SetModified(sal_True); 2323 } 2324 #endif 2325 } 2326 /*-- 08.09.2008 11:33:02--------------------------------------------------- 2327 2328 -----------------------------------------------------------------------*/ 2329 void ImpEditEngine::PutSpellingToSentenceStart( EditView& rEditView ) 2330 { 2331 #ifdef SVX_LIGHT 2332 #else 2333 if( pSpellInfo && pSpellInfo->aLastSpellContentSelections.size() ) 2334 { 2335 rEditView.pImpEditView->SetEditSelection( pSpellInfo->aLastSpellContentSelections.begin()->Min() ); 2336 } 2337 2338 #endif 2339 } 2340 2341 2342 void ImpEditEngine::DoOnlineSpelling( ContentNode* pThisNodeOnly, sal_Bool bSpellAtCursorPos, sal_Bool bInteruptable ) 2343 { 2344 #ifndef SVX_LIGHT 2345 /* 2346 Er wird ueber alle Absaetze iteriert, nur Absaetze mit invalidierter 2347 WrongList werden geprueft... 2348 2349 Es werden alle Woerter im invalidierten Bereich geprueft. 2350 Ist ein Wort falsch, aber noch nicht in der WrongList, oder umgekehrt, 2351 wird der Bereich des Wortes invalidiert 2352 ( kein Invalidate, sondern wenn nur Uebergaenge von richtig=>falsch, 2353 einfaches Paint, bei Uebergaengen von falsch=>richtig mit VDev 2354 ueberplaetten ) 2355 */ 2356 2357 if ( !xSpeller.is() ) 2358 return; 2359 2360 EditPaM aCursorPos; 2361 if( pActiveView && !bSpellAtCursorPos ) 2362 { 2363 DBG_CHKOBJ( pActiveView, EditView, 0 ); 2364 aCursorPos = pActiveView->pImpEditView->GetEditSelection().Max(); 2365 } 2366 sal_Bool bRestartTimer = sal_False; 2367 2368 ContentNode* pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count() - 1 ); 2369 sal_uInt16 nNodes = GetEditDoc().Count(); 2370 sal_uInt16 nInvalids = 0; 2371 Sequence< PropertyValue > aEmptySeq; 2372 for ( sal_uInt16 n = 0; n < nNodes; n++ ) 2373 { 2374 ContentNode* pNode = GetEditDoc().GetObject( n ); 2375 if ( pThisNodeOnly ) 2376 pNode = pThisNodeOnly; 2377 2378 if ( pNode->GetWrongList()->IsInvalid() ) 2379 { 2380 WrongList* pWrongList = pNode->GetWrongList(); 2381 sal_uInt16 nInvStart = pWrongList->GetInvalidStart(); 2382 sal_uInt16 nInvEnd = pWrongList->GetInvalidEnd(); 2383 2384 sal_uInt16 nWrongs = 0; // Auch im Absatz mal die Kontrolle abgeben... 2385 // sal_Bool bStop = sal_False; 2386 2387 sal_uInt16 nPaintFrom = 0xFFFF, nPaintTo = 0; 2388 sal_Bool bSimpleRepaint = sal_True; 2389 2390 pWrongList->SetValid(); 2391 2392 EditPaM aPaM( pNode, nInvStart ); 2393 EditSelection aSel( aPaM, aPaM ); 2394 while ( ( aSel.Max().GetNode() == pNode ) /* && !bStop */ ) 2395 { 2396 if ( ( aSel.Min().GetIndex() > nInvEnd ) 2397 || ( ( aSel.Max().GetNode() == pLastNode ) && ( aSel.Max().GetIndex() >= pLastNode->Len() ) ) ) 2398 break; // Dokument- oder Ungueltigkeitsbereich-Ende 2399 2400 aSel = SelectWord( aSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 2401 String aWord( GetSelected( aSel ) ); 2402 // Wenn Punkt dahinter, muss dieser mit uebergeben werden ! 2403 // Falls Abkuerzung... 2404 sal_Bool bDottAdded = sal_False; 2405 if ( aSel.Max().GetIndex() < aSel.Max().GetNode()->Len() ) 2406 { 2407 sal_Unicode cNext = aSel.Max().GetNode()->GetChar( aSel.Max().GetIndex() ); 2408 if ( cNext == '.' ) 2409 { 2410 aSel.Max().GetIndex()++; 2411 aWord += cNext; 2412 bDottAdded = sal_True; 2413 } 2414 } 2415 2416 2417 sal_Bool bChanged = sal_False; 2418 if ( aWord.Len() > 0 ) 2419 { 2420 sal_uInt16 nWStart = aSel.Min().GetIndex(); 2421 sal_uInt16 nWEnd= aSel.Max().GetIndex(); 2422 if ( !xSpeller->isValid( aWord, GetLanguage( EditPaM( aSel.Min().GetNode(), nWStart+1 ) ), aEmptySeq ) ) 2423 { 2424 // Pruefen, ob schon richtig markiert... 2425 nWrongs++; 2426 // Nur bei SimpleRepaint stoppen, sonst zu oft VDev 2427 // if ( ( nWrongs > 8 ) && bSimpleRepaint ) 2428 // { 2429 // bStop = sal_True; 2430 // pWrongList->MarkInvalid( aSel.Max().GetIndex(), nInvEnd ); 2431 // } 2432 sal_uInt16 nXEnd = bDottAdded ? nWEnd -1 : nWEnd; 2433 if ( !pWrongList->HasWrong( nWStart, nXEnd ) ) 2434 { 2435 // Wort als falsch markieren... 2436 // Aber nur, wenn nicht an Cursor-Position... 2437 sal_Bool bCursorPos = sal_False; 2438 if ( aCursorPos.GetNode() == pNode ) 2439 { 2440 if ( ( nWStart <= aCursorPos.GetIndex() ) && nWEnd >= aCursorPos.GetIndex() ) 2441 bCursorPos = sal_True; 2442 } 2443 if ( bCursorPos ) 2444 { 2445 // Dann weiter als ungueltig markieren... 2446 pWrongList->GetInvalidStart() = nWStart; 2447 pWrongList->GetInvalidEnd() = nWEnd; 2448 bRestartTimer = sal_True; 2449 } 2450 else 2451 { 2452 // Es kann sein, dass die Wrongs in der Liste nicht 2453 // genau ueber Woerter aufgespannt sind, weil die 2454 // WordDelimiters beim Expandieren nicht ausgewrtet werden. 2455 pWrongList->InsertWrong( nWStart, nXEnd, sal_True ); 2456 bChanged = sal_True; 2457 } 2458 } 2459 } 2460 else 2461 { 2462 // Pruefen, ob nicht als als falsch markiert.... 2463 if ( pWrongList->HasAnyWrong( nWStart, nWEnd ) ) 2464 { 2465 pWrongList->ClearWrongs( nWStart, nWEnd, pNode ); 2466 bSimpleRepaint = sal_False; 2467 bChanged = sal_True; 2468 } 2469 } 2470 if ( bChanged ) 2471 { 2472 if ( nPaintFrom == 0xFFFF ) 2473 nPaintFrom = nWStart; 2474 nPaintTo = nWEnd; 2475 } 2476 } 2477 2478 EditPaM aLastEnd( aSel.Max() ); 2479 aSel = WordRight( aSel.Max(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 2480 if ( bChanged && ( aSel.Min().GetNode() == pNode ) && 2481 ( ( aSel.Min().GetIndex()-aLastEnd.GetIndex() > 1 ) ) ) 2482 { 2483 // Wenn zwei Worte durch mehr Zeichen als ein Blank getrennt 2484 // sind, kann es passieren, dass beim Aufsplitten eines Wrongs 2485 // der Start den zweiten Wortes vor dem tatsaechlich Wort liegt 2486 pWrongList->ClearWrongs( aLastEnd.GetIndex(), aSel.Min().GetIndex(), pNode ); 2487 } 2488 } 2489 2490 // Invalidieren? 2491 if ( ( nPaintFrom != 0xFFFF ) ) 2492 { 2493 aStatus.GetStatusWord() |= EE_STAT_WRONGWORDCHANGED; 2494 CallStatusHdl(); 2495 2496 if ( aEditViews.Count() ) 2497 { 2498 // Bei SimpleRepaint wuerde ein uebermalen ohne VDev reichen, 2499 // aber dann muesste ich ueber alle Views, Intersecten, 2500 // Clippen, ... 2501 // Lohnt wahrscheinlich nicht. 2502 EditPaM aStartPaM( pNode, nPaintFrom ); 2503 EditPaM aEndPaM( pNode, nPaintTo ); 2504 Rectangle aStartCursor( PaMtoEditCursor( aStartPaM ) ); 2505 Rectangle aEndCursor( PaMtoEditCursor( aEndPaM ) ); 2506 DBG_ASSERT( aInvalidRec.IsEmpty(), "InvalidRect gesetzt!" ); 2507 aInvalidRec.Left() = 0; 2508 aInvalidRec.Right() = GetPaperSize().Width(); 2509 aInvalidRec.Top() = aStartCursor.Top(); 2510 aInvalidRec.Bottom() = aEndCursor.Bottom(); 2511 if ( pActiveView && pActiveView->HasSelection() ) 2512 { 2513 // Dann darf nicht ueber VDev ausgegeben werden 2514 UpdateViews( NULL ); 2515 } 2516 else if ( bSimpleRepaint ) 2517 { 2518 for ( sal_uInt16 nView = 0; nView < aEditViews.Count(); nView++ ) 2519 { 2520 EditView* pView = aEditViews[nView]; 2521 Rectangle aClipRec( aInvalidRec ); 2522 aClipRec.Intersection( pView->GetVisArea() ); 2523 if ( !aClipRec.IsEmpty() ) 2524 { 2525 // in Fensterkoordinaten umwandeln.... 2526 aClipRec.SetPos( pView->pImpEditView->GetWindowPos( aClipRec.TopLeft() ) ); 2527 // Wenn Selektion, dann VDev... 2528 Paint( pView->pImpEditView, aClipRec, pView->HasSelection() ); 2529 } 2530 } 2531 } 2532 else 2533 { 2534 UpdateViews( pActiveView ); 2535 } 2536 aInvalidRec = Rectangle(); 2537 } 2538 } 2539 // Nach zwei korrigierten Nodes die Kontrolle abgeben... 2540 nInvalids++; 2541 if ( bInteruptable && ( nInvalids >= 2 ) ) 2542 { 2543 bRestartTimer = sal_True; 2544 break; 2545 } 2546 } 2547 2548 if ( pThisNodeOnly ) 2549 break; 2550 } 2551 if ( bRestartTimer ) 2552 aOnlineSpellTimer.Start(); 2553 #endif // !SVX_LIGHT 2554 } 2555 2556 2557 EESpellState ImpEditEngine::HasSpellErrors() 2558 { 2559 DBG_ASSERT( xSpeller.is(), "Kein Speller gesetzt!" ); 2560 2561 #ifndef SVX_LIGHT 2562 ContentNode* pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count() - 1 ); 2563 EditSelection aCurSel( aEditDoc.GetStartPaM() ); 2564 2565 String aWord; 2566 Reference< XSpellAlternatives > xSpellAlt; 2567 Sequence< PropertyValue > aEmptySeq; 2568 while ( !xSpellAlt.is() ) 2569 { 2570 if ( ( aCurSel.Max().GetNode() == pLastNode ) && 2571 ( aCurSel.Max().GetIndex() >= pLastNode->Len() ) ) 2572 { 2573 return EE_SPELL_OK; 2574 } 2575 2576 aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 2577 aWord = GetSelected( aCurSel ); 2578 if ( aWord.Len() > 0 ) 2579 { 2580 LanguageType eLang = GetLanguage( aCurSel.Max() ); 2581 SvxSpellWrapper::CheckSpellLang( xSpeller, eLang ); 2582 xSpellAlt = xSpeller->spell( aWord, eLang, aEmptySeq ); 2583 } 2584 aCurSel = WordRight( aCurSel.Max(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 2585 } 2586 #endif 2587 2588 return EE_SPELL_ERRORFOUND; 2589 } 2590 2591 EESpellState ImpEditEngine::StartThesaurus( EditView* pEditView ) 2592 { 2593 #ifndef SVX_LIGHT 2594 EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); 2595 if ( !aCurSel.HasRange() ) 2596 aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 2597 String aWord( GetSelected( aCurSel ) ); 2598 2599 Reference< XThesaurus > xThes( SvxGetThesaurus() ); 2600 if (!xThes.is()) 2601 return EE_SPELL_ERRORFOUND; 2602 2603 EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create(); 2604 AbstractThesaurusDialog* pDlg = pFact->CreateThesaurusDialog( pEditView->GetWindow(), xThes, aWord, GetLanguage( aCurSel.Max() ) ); 2605 if ( pDlg->Execute() == RET_OK ) 2606 { 2607 // Wort ersetzen... 2608 pEditView->pImpEditView->DrawSelection(); 2609 pEditView->pImpEditView->SetEditSelection( aCurSel ); 2610 pEditView->pImpEditView->DrawSelection(); 2611 pEditView->InsertText( pDlg->GetWord() ); 2612 pEditView->ShowCursor( sal_True, sal_False ); 2613 } 2614 2615 delete pDlg; 2616 return EE_SPELL_OK; 2617 #else 2618 return EE_SPELL_NOSPELLER; 2619 #endif 2620 } 2621 2622 sal_uInt16 ImpEditEngine::StartSearchAndReplace( EditView* pEditView, const SvxSearchItem& rSearchItem ) 2623 { 2624 sal_uInt16 nFound = 0; 2625 2626 #ifndef SVX_LIGHT 2627 EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); 2628 2629 // FIND_ALL ohne Mehrfachselektion nicht moeglich. 2630 if ( ( rSearchItem.GetCommand() == SVX_SEARCHCMD_FIND ) || 2631 ( rSearchItem.GetCommand() == SVX_SEARCHCMD_FIND_ALL ) ) 2632 { 2633 if ( Search( rSearchItem, pEditView ) ) 2634 nFound++; 2635 } 2636 else if ( rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE ) 2637 { 2638 // Das Wort ist selektiert, wenn der Anwender die Selektion 2639 // nicht zwischendurch manipuliert: 2640 if ( aCurSel.HasRange() ) 2641 { 2642 pEditView->InsertText( rSearchItem.GetReplaceString() ); 2643 nFound = 1; 2644 } 2645 else 2646 if( Search( rSearchItem, pEditView ) ) 2647 nFound = 1; 2648 } 2649 else if ( rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL ) 2650 { 2651 // Der Writer ersetzt alle, vorn Anfang bis Ende... 2652 SvxSearchItem aTmpItem( rSearchItem ); 2653 aTmpItem.SetBackward( sal_False ); 2654 2655 pEditView->pImpEditView->DrawSelection(); 2656 2657 aCurSel.Adjust( aEditDoc ); 2658 EditPaM aStartPaM = aTmpItem.GetSelection() ? aCurSel.Min() : aEditDoc.GetStartPaM(); 2659 EditSelection aFoundSel( aCurSel.Max() ); 2660 sal_Bool bFound = ImpSearch( aTmpItem, aCurSel, aStartPaM, aFoundSel ); 2661 if ( bFound ) 2662 UndoActionStart( EDITUNDO_REPLACEALL ); 2663 while ( bFound ) 2664 { 2665 nFound++; 2666 aStartPaM = ImpInsertText( aFoundSel, rSearchItem.GetReplaceString() ); 2667 bFound = ImpSearch( aTmpItem, aCurSel, aStartPaM, aFoundSel ); 2668 } 2669 if ( nFound ) 2670 { 2671 EditPaM aNewPaM( aFoundSel.Max() ); 2672 if ( aNewPaM.GetIndex() > aNewPaM.GetNode()->Len() ) 2673 aNewPaM.GetIndex() = aNewPaM.GetNode()->Len(); 2674 pEditView->pImpEditView->SetEditSelection( aNewPaM ); 2675 FormatAndUpdate( pEditView ); 2676 UndoActionEnd( EDITUNDO_REPLACEALL ); 2677 } 2678 else 2679 { 2680 pEditView->pImpEditView->DrawSelection(); 2681 pEditView->ShowCursor( sal_True, sal_False ); 2682 } 2683 } 2684 #endif // !SVX_LIGHT 2685 return nFound; 2686 } 2687 2688 sal_Bool ImpEditEngine::Search( const SvxSearchItem& rSearchItem, EditView* pEditView ) 2689 { 2690 EditSelection aSel( pEditView->pImpEditView->GetEditSelection() ); 2691 aSel.Adjust( aEditDoc ); 2692 EditPaM aStartPaM( aSel.Max() ); 2693 if ( rSearchItem.GetSelection() && !rSearchItem.GetBackward() ) 2694 aStartPaM = aSel.Min(); 2695 2696 EditSelection aFoundSel; 2697 sal_Bool bFound = ImpSearch( rSearchItem, aSel, aStartPaM, aFoundSel ); 2698 if ( bFound && ( aFoundSel == aSel ) ) // Bei Rueckwaetssuche 2699 { 2700 aStartPaM = aSel.Min(); 2701 bFound = ImpSearch( rSearchItem, aSel, aStartPaM, aFoundSel ); 2702 } 2703 2704 pEditView->pImpEditView->DrawSelection(); 2705 if ( bFound ) 2706 { 2707 // Erstmal das Min einstellen, damit das ganze Wort in den sichtbaren Bereich kommt. 2708 pEditView->pImpEditView->SetEditSelection( aFoundSel.Min() ); 2709 pEditView->ShowCursor( sal_True, sal_False ); 2710 pEditView->pImpEditView->SetEditSelection( aFoundSel ); 2711 } 2712 else 2713 pEditView->pImpEditView->SetEditSelection( aSel.Max() ); 2714 2715 pEditView->pImpEditView->DrawSelection(); 2716 pEditView->ShowCursor( sal_True, sal_False ); 2717 return bFound; 2718 } 2719 2720 sal_Bool ImpEditEngine::ImpSearch( const SvxSearchItem& rSearchItem, 2721 const EditSelection& rSearchSelection, const EditPaM& rStartPos, EditSelection& rFoundSel ) 2722 { 2723 #ifndef SVX_LIGHT 2724 util::SearchOptions aSearchOptions( rSearchItem.GetSearchOptions() ); 2725 aSearchOptions.Locale = GetLocale( rStartPos ); 2726 2727 sal_Bool bBack = rSearchItem.GetBackward(); 2728 sal_Bool bSearchInSelection = rSearchItem.GetSelection(); 2729 sal_uInt16 nStartNode = aEditDoc.GetPos( rStartPos.GetNode() ); 2730 sal_uInt16 nEndNode; 2731 if ( bSearchInSelection ) 2732 { 2733 nEndNode = aEditDoc.GetPos( bBack ? rSearchSelection.Min().GetNode() : rSearchSelection.Max().GetNode() ); 2734 } 2735 else 2736 { 2737 nEndNode = bBack ? 0 : aEditDoc.Count()-1; 2738 } 2739 2740 utl::TextSearch aSearcher( aSearchOptions ); 2741 2742 // ueber die Absaetze iterieren... 2743 for ( sal_uInt16 nNode = nStartNode; 2744 bBack ? ( nNode >= nEndNode ) : ( nNode <= nEndNode) ; 2745 bBack ? nNode-- : nNode++ ) 2746 { 2747 // Bei rueckwaertsuche, wenn nEndNode = 0: 2748 if ( nNode >= 0xFFFF ) 2749 return sal_False; 2750 2751 ContentNode* pNode = aEditDoc.GetObject( nNode ); 2752 2753 sal_uInt16 nStartPos = 0; 2754 sal_uInt16 nEndPos = pNode->Len(); 2755 if ( nNode == nStartNode ) 2756 { 2757 if ( bBack ) 2758 nEndPos = rStartPos.GetIndex(); 2759 else 2760 nStartPos = rStartPos.GetIndex(); 2761 } 2762 if ( ( nNode == nEndNode ) && bSearchInSelection ) 2763 { 2764 if ( bBack ) 2765 nStartPos = rSearchSelection.Min().GetIndex(); 2766 else 2767 nEndPos = rSearchSelection.Max().GetIndex(); 2768 } 2769 2770 // Suchen... 2771 XubString aParaStr( GetEditDoc().GetParaAsString( pNode ) ); 2772 bool bFound = false; 2773 if ( bBack ) 2774 { 2775 Swapsal_uIt16s( nStartPos, nEndPos ); 2776 bFound = aSearcher.SearchBkwrd( aParaStr, &nStartPos, &nEndPos); 2777 } 2778 else 2779 bFound = aSearcher.SearchFrwrd( aParaStr, &nStartPos, &nEndPos); 2780 2781 if ( bFound ) 2782 { 2783 rFoundSel.Min().SetNode( pNode ); 2784 rFoundSel.Min().SetIndex( nStartPos ); 2785 rFoundSel.Max().SetNode( pNode ); 2786 rFoundSel.Max().SetIndex( nEndPos ); 2787 return sal_True; 2788 } 2789 } 2790 #endif // !SVX_LIGHT 2791 return sal_False; 2792 } 2793 2794 sal_Bool ImpEditEngine::HasText( const SvxSearchItem& rSearchItem ) 2795 { 2796 #ifndef SVX_LIGHT 2797 SvxSearchItem aTmpItem( rSearchItem ); 2798 aTmpItem.SetBackward( sal_False ); 2799 aTmpItem.SetSelection( sal_False ); 2800 2801 EditPaM aStartPaM( aEditDoc.GetStartPaM() ); 2802 EditSelection aDummySel( aStartPaM ); 2803 EditSelection aFoundSel; 2804 return ImpSearch( aTmpItem, aDummySel, aStartPaM, aFoundSel ); 2805 #else 2806 return sal_False; 2807 #endif 2808 } 2809 2810 void ImpEditEngine::SetAutoCompleteText( const String& rStr, sal_Bool bClearTipWindow ) 2811 { 2812 #ifndef SVX_LIGHT 2813 aAutoCompleteText = rStr; 2814 if ( bClearTipWindow && pActiveView ) 2815 Help::ShowQuickHelp( pActiveView->GetWindow(), Rectangle(), String(), 0 ); 2816 #endif // !SVX_LIGHT 2817 } 2818 2819 2820 struct TransliterationChgData 2821 { 2822 sal_uInt16 nStart; 2823 xub_StrLen nLen; 2824 EditSelection aSelection; 2825 String aNewText; 2826 uno::Sequence< sal_Int32 > aOffsets; 2827 }; 2828 2829 2830 EditSelection ImpEditEngine::TransliterateText( const EditSelection& rSelection, sal_Int32 nTransliterationMode ) 2831 { 2832 uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); 2833 if (!_xBI.is()) 2834 return rSelection; 2835 2836 EditSelection aSel( rSelection ); 2837 aSel.Adjust( aEditDoc ); 2838 2839 if ( !aSel.HasRange() ) 2840 aSel = SelectWord( aSel ); 2841 2842 EditSelection aNewSel( aSel ); 2843 2844 const sal_uInt16 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); 2845 const sal_uInt16 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); 2846 2847 sal_Bool bChanges = sal_False; 2848 sal_Bool bLenChanged = sal_False; 2849 EditUndoTransliteration* pUndo = NULL; 2850 2851 utl::TransliterationWrapper aTranslitarationWrapper( ::comphelper::getProcessServiceFactory(), nTransliterationMode ); 2852 sal_Bool bConsiderLanguage = aTranslitarationWrapper.needLanguageForTheMode(); 2853 2854 for ( sal_uInt16 nNode = nStartNode; nNode <= nEndNode; nNode++ ) 2855 { 2856 ContentNode* pNode = aEditDoc.GetObject( nNode ); 2857 xub_StrLen nStartPos = 0; 2858 xub_StrLen nEndPos = pNode->Len(); 2859 if ( nNode == nStartNode ) 2860 nStartPos = aSel.Min().GetIndex(); 2861 if ( nNode == nEndNode ) // kann auch == nStart sein! 2862 nEndPos = aSel.Max().GetIndex(); 2863 2864 sal_uInt16 nCurrentStart = nStartPos; 2865 sal_uInt16 nCurrentEnd = nEndPos; 2866 sal_uInt16 nLanguage = LANGUAGE_SYSTEM; 2867 2868 // since we don't use Hiragana/Katakana or half-width/full-width transliterations here 2869 // it is fine to use ANYWORD_IGNOREWHITESPACES. (ANY_WORD btw is broken and will 2870 // occasionaly miss words in consecutive sentences). Also with ANYWORD_IGNOREWHITESPACES 2871 // text like 'just-in-time' will be converted to 'Just-In-Time' which seems to be the 2872 // proper thing to do. 2873 const sal_Int16 nWordType = i18n::WordType::ANYWORD_IGNOREWHITESPACES; 2874 2875 //! In order to have less trouble with changing text size, e.g. because 2876 //! of ligatures or � (German small sz) being resolved, we need to process 2877 //! the text replacements from end to start. 2878 //! This way the offsets for the yet to be changed words will be 2879 //! left unchanged by the already replaced text. 2880 //! For this we temporarily save the changes to be done in this vector 2881 std::vector< TransliterationChgData > aChanges; 2882 TransliterationChgData aChgData; 2883 2884 if (nTransliterationMode == i18n::TransliterationModulesExtra::TITLE_CASE) 2885 { 2886 // for 'capitalize every word' we need to iterate over each word 2887 2888 i18n::Boundary aSttBndry; 2889 i18n::Boundary aEndBndry; 2890 aSttBndry = _xBI->getWordBoundary( 2891 *pNode, nStartPos, 2892 SvxCreateLocale( GetLanguage( EditPaM( pNode, nStartPos + 1 ) ) ), 2893 nWordType, sal_True /*prefer forward direction*/); 2894 aEndBndry = _xBI->getWordBoundary( 2895 *pNode, nEndPos, 2896 SvxCreateLocale( GetLanguage( EditPaM( pNode, nEndPos + 1 ) ) ), 2897 nWordType, sal_False /*prefer backward direction*/); 2898 2899 // prevent backtracking to the previous word if selection is at word boundary 2900 if (aSttBndry.endPos <= nStartPos) 2901 { 2902 aSttBndry = _xBI->nextWord( 2903 *pNode, aSttBndry.endPos, 2904 SvxCreateLocale( GetLanguage( EditPaM( pNode, aSttBndry.endPos + 1 ) ) ), 2905 nWordType); 2906 } 2907 // prevent advancing to the next word if selection is at word boundary 2908 if (aEndBndry.startPos >= nEndPos) 2909 { 2910 aEndBndry = _xBI->previousWord( 2911 *pNode, aEndBndry.startPos, 2912 SvxCreateLocale( GetLanguage( EditPaM( pNode, aEndBndry.startPos + 1 ) ) ), 2913 nWordType); 2914 } 2915 2916 i18n::Boundary aCurWordBndry( aSttBndry ); 2917 while (aCurWordBndry.startPos <= aEndBndry.startPos) 2918 { 2919 nCurrentStart = (xub_StrLen)aCurWordBndry.startPos; 2920 nCurrentEnd = (xub_StrLen)aCurWordBndry.endPos; 2921 sal_Int32 nLen = nCurrentEnd - nCurrentStart; 2922 DBG_ASSERT( nLen > 0, "invalid word length of 0" ); 2923 #if OSL_DEBUG_LEVEL > 1 2924 String aText( pNode->Copy( nCurrentStart, nLen ) ); 2925 #endif 2926 2927 Sequence< sal_Int32 > aOffsets; 2928 String aNewText( aTranslitarationWrapper.transliterate( *pNode, 2929 GetLanguage( EditPaM( pNode, nCurrentStart + 1 ) ), 2930 nCurrentStart, nLen, &aOffsets )); 2931 2932 if (!pNode->Equals( aNewText, nCurrentStart, nLen )) 2933 { 2934 aChgData.nStart = nCurrentStart; 2935 aChgData.nLen = nLen; 2936 aChgData.aSelection = EditSelection( EditPaM( pNode, nCurrentStart ), EditPaM( pNode, nCurrentEnd ) ); 2937 aChgData.aNewText = aNewText; 2938 aChgData.aOffsets = aOffsets; 2939 aChanges.push_back( aChgData ); 2940 } 2941 #if OSL_DEBUG_LEVEL > 1 2942 String aSelTxt ( GetSelected( aChgData.aSelection ) ); 2943 (void) aSelTxt; 2944 #endif 2945 2946 aCurWordBndry = _xBI->nextWord( *pNode, nCurrentEnd, 2947 SvxCreateLocale( GetLanguage( EditPaM( pNode, nCurrentEnd + 1 ) ) ), 2948 nWordType); 2949 } 2950 DBG_ASSERT( nCurrentEnd >= aEndBndry.endPos, "failed to reach end of transliteration" ); 2951 } 2952 else if (nTransliterationMode == i18n::TransliterationModulesExtra::SENTENCE_CASE) 2953 { 2954 // for 'sentence case' we need to iterate sentence by sentence 2955 2956 sal_Int32 nLastStart = _xBI->beginOfSentence( 2957 *pNode, nEndPos, 2958 SvxCreateLocale( GetLanguage( EditPaM( pNode, nEndPos + 1 ) ) ) ); 2959 sal_Int32 nLastEnd = _xBI->endOfSentence( 2960 *pNode, nLastStart, 2961 SvxCreateLocale( GetLanguage( EditPaM( pNode, nLastStart + 1 ) ) ) ); 2962 2963 // extend nCurrentStart, nCurrentEnd to the current sentence boundaries 2964 nCurrentStart = _xBI->beginOfSentence( 2965 *pNode, nStartPos, 2966 SvxCreateLocale( GetLanguage( EditPaM( pNode, nStartPos + 1 ) ) ) ); 2967 nCurrentEnd = _xBI->endOfSentence( 2968 *pNode, nCurrentStart, 2969 SvxCreateLocale( GetLanguage( EditPaM( pNode, nCurrentStart + 1 ) ) ) ); 2970 2971 // prevent backtracking to the previous sentence if selection starts at end of a sentence 2972 if (nCurrentEnd <= nStartPos) 2973 { 2974 // now nCurrentStart is probably located on a non-letter word. (unless we 2975 // are in Asian text with no spaces...) 2976 // Thus to get the real sentence start we should locate the next real word, 2977 // that is one found by DICTIONARY_WORD 2978 i18n::Boundary aBndry = _xBI->nextWord( *pNode, nCurrentEnd, 2979 SvxCreateLocale( GetLanguage( EditPaM( pNode, nCurrentEnd + 1 ) ) ), 2980 i18n::WordType::DICTIONARY_WORD); 2981 2982 // now get new current sentence boundaries 2983 nCurrentStart = _xBI->beginOfSentence( 2984 *pNode, aBndry.startPos, 2985 SvxCreateLocale( GetLanguage( EditPaM( pNode, aBndry.startPos + 1 ) ) ) ); 2986 nCurrentEnd = _xBI->endOfSentence( 2987 *pNode, nCurrentStart, 2988 SvxCreateLocale( GetLanguage( EditPaM( pNode, nCurrentStart + 1 ) ) ) ); 2989 } 2990 // prevent advancing to the next sentence if selection ends at start of a sentence 2991 if (nLastStart >= nEndPos) 2992 { 2993 // now nCurrentStart is probably located on a non-letter word. (unless we 2994 // are in Asian text with no spaces...) 2995 // Thus to get the real sentence start we should locate the previous real word, 2996 // that is one found by DICTIONARY_WORD 2997 i18n::Boundary aBndry = _xBI->previousWord( *pNode, nLastStart, 2998 SvxCreateLocale( GetLanguage( EditPaM( pNode, nLastStart + 1 ) ) ), 2999 i18n::WordType::DICTIONARY_WORD); 3000 nLastEnd = _xBI->endOfSentence( 3001 *pNode, aBndry.startPos, 3002 SvxCreateLocale( GetLanguage( EditPaM( pNode, aBndry.startPos + 1 ) ) ) ); 3003 if (nCurrentEnd > nLastEnd) 3004 nCurrentEnd = nLastEnd; 3005 } 3006 3007 while (nCurrentStart < nLastEnd) 3008 { 3009 sal_Int32 nLen = nCurrentEnd - nCurrentStart; 3010 DBG_ASSERT( nLen > 0, "invalid word length of 0" ); 3011 #if OSL_DEBUG_LEVEL > 1 3012 String aText( pNode->Copy( nCurrentStart, nLen ) ); 3013 #endif 3014 3015 Sequence< sal_Int32 > aOffsets; 3016 String aNewText( aTranslitarationWrapper.transliterate( *pNode, 3017 GetLanguage( EditPaM( pNode, nCurrentStart + 1 ) ), 3018 nCurrentStart, nLen, &aOffsets )); 3019 3020 if (!pNode->Equals( aNewText, nCurrentStart, nLen )) 3021 { 3022 aChgData.nStart = nCurrentStart; 3023 aChgData.nLen = nLen; 3024 aChgData.aSelection = EditSelection( EditPaM( pNode, nCurrentStart ), EditPaM( pNode, nCurrentEnd ) ); 3025 aChgData.aNewText = aNewText; 3026 aChgData.aOffsets = aOffsets; 3027 aChanges.push_back( aChgData ); 3028 } 3029 3030 i18n::Boundary aFirstWordBndry; 3031 aFirstWordBndry = _xBI->nextWord( 3032 *pNode, nCurrentEnd, 3033 SvxCreateLocale( GetLanguage( EditPaM( pNode, nCurrentEnd + 1 ) ) ), 3034 nWordType); 3035 nCurrentStart = aFirstWordBndry.startPos; 3036 nCurrentEnd = _xBI->endOfSentence( 3037 *pNode, nCurrentStart, 3038 SvxCreateLocale( GetLanguage( EditPaM( pNode, nCurrentStart + 1 ) ) ) ); 3039 } 3040 DBG_ASSERT( nCurrentEnd >= nLastEnd, "failed to reach end of transliteration" ); 3041 } 3042 else 3043 { 3044 do 3045 { 3046 if ( bConsiderLanguage ) 3047 { 3048 nLanguage = GetLanguage( EditPaM( pNode, nCurrentStart+1 ), &nCurrentEnd ); 3049 if ( nCurrentEnd > nEndPos ) 3050 nCurrentEnd = nEndPos; 3051 } 3052 3053 xub_StrLen nLen = nCurrentEnd - nCurrentStart; 3054 3055 Sequence< sal_Int32 > aOffsets; 3056 String aNewText( aTranslitarationWrapper.transliterate( *pNode, nLanguage, nCurrentStart, nLen, &aOffsets ) ); 3057 3058 if (!pNode->Equals( aNewText, nCurrentStart, nLen )) 3059 { 3060 aChgData.nStart = nCurrentStart; 3061 aChgData.nLen = nLen; 3062 aChgData.aSelection = EditSelection( EditPaM( pNode, nCurrentStart ), EditPaM( pNode, nCurrentEnd ) ); 3063 aChgData.aNewText = aNewText; 3064 aChgData.aOffsets = aOffsets; 3065 aChanges.push_back( aChgData ); 3066 } 3067 3068 nCurrentStart = nCurrentEnd; 3069 } while( nCurrentEnd < nEndPos ); 3070 } 3071 3072 if (aChanges.size() > 0) 3073 { 3074 #ifndef SVX_LIGHT 3075 // Create a single UndoAction on Demand for all the changes ... 3076 if ( !pUndo && IsUndoEnabled() && !IsInUndo() ) 3077 { 3078 // adjust selection to include all changes 3079 for (size_t i = 0; i < aChanges.size(); ++i) 3080 { 3081 const EditSelection &rSel = aChanges[i].aSelection; 3082 if (aSel.Min().GetNode() == rSel.Min().GetNode() && 3083 aSel.Min().GetIndex() > rSel.Min().GetIndex()) 3084 aSel.Min().SetIndex( rSel.Min().GetIndex() ); 3085 if (aSel.Max().GetNode() == rSel.Max().GetNode() && 3086 aSel.Max().GetIndex() < rSel.Max().GetIndex()) 3087 aSel.Max().SetIndex( rSel.Max().GetIndex() ); 3088 } 3089 aNewSel = aSel; 3090 3091 ESelection aESel( CreateESel( aSel ) ); 3092 pUndo = new EditUndoTransliteration( this, aESel, nTransliterationMode ); 3093 3094 const bool bSingleNode = aSel.Min().GetNode()== aSel.Max().GetNode(); 3095 const bool bHasAttribs = aSel.Min().GetNode()->GetCharAttribs().HasAttrib( aSel.Min().GetIndex(), aSel.Max().GetIndex() ); 3096 if (bSingleNode && !bHasAttribs) 3097 pUndo->SetText( aSel.Min().GetNode()->Copy( aSel.Min().GetIndex(), aSel.Max().GetIndex()-aSel.Min().GetIndex() ) ); 3098 else 3099 pUndo->SetText( CreateBinTextObject( aSel, NULL ) ); 3100 } 3101 #endif 3102 3103 // now apply the changes from end to start to leave the offsets of the 3104 // yet unchanged text parts remain the same. 3105 for (size_t i = 0; i < aChanges.size(); ++i) 3106 { 3107 const TransliterationChgData &rData = aChanges[ aChanges.size() - 1 - i ]; 3108 3109 bChanges = sal_True; 3110 if (rData.nLen != rData.aNewText.Len()) 3111 bLenChanged = sal_True; 3112 3113 // Change text without loosing the attributes 3114 sal_uInt16 nDiffs = ReplaceTextOnly( rData.aSelection.Min().GetNode(), 3115 rData.nStart, rData.nLen, rData.aNewText, rData.aOffsets ); 3116 3117 // adjust selection in end node to possibly changed size 3118 if (aSel.Max().GetNode() == rData.aSelection.Max().GetNode()) 3119 aNewSel.Max().GetIndex() = aNewSel.Max().GetIndex() + nDiffs; 3120 3121 sal_uInt16 nSelNode = aEditDoc.GetPos( rData.aSelection.Min().GetNode() ); 3122 ParaPortion* pParaPortion = GetParaPortions()[nSelNode]; 3123 pParaPortion->MarkSelectionInvalid( rData.nStart, 3124 std::max< sal_uInt16 >( rData.nStart + rData.nLen, 3125 rData.nStart + rData.aNewText.Len() ) ); 3126 } 3127 } // if (aChanges.size() > 0) 3128 } 3129 3130 #ifndef SVX_LIGHT 3131 if ( pUndo ) 3132 { 3133 ESelection aESel( CreateESel( aNewSel ) ); 3134 pUndo->SetNewSelection( aESel ); 3135 InsertUndo( pUndo ); 3136 } 3137 #endif 3138 3139 if ( bChanges ) 3140 { 3141 TextModified(); 3142 SetModifyFlag( sal_True ); 3143 if ( bLenChanged ) 3144 UpdateSelections(); 3145 FormatAndUpdate(); 3146 } 3147 3148 return aNewSel; 3149 } 3150 3151 3152 short ImpEditEngine::ReplaceTextOnly( 3153 ContentNode* pNode, 3154 sal_uInt16 nCurrentStart, xub_StrLen nLen, 3155 const String& rNewText, 3156 const uno::Sequence< sal_Int32 >& rOffsets ) 3157 { 3158 (void) nLen; 3159 3160 // Change text without loosing the attributes 3161 sal_uInt16 nCharsAfterTransliteration = 3162 sal::static_int_cast< sal_uInt16 >(rOffsets.getLength()); 3163 const sal_Int32* pOffsets = rOffsets.getConstArray(); 3164 short nDiffs = 0; 3165 for ( sal_uInt16 n = 0; n < nCharsAfterTransliteration; n++ ) 3166 { 3167 sal_uInt16 nCurrentPos = nCurrentStart+n; 3168 sal_Int32 nDiff = (nCurrentPos-nDiffs) - pOffsets[n]; 3169 3170 if ( !nDiff ) 3171 { 3172 DBG_ASSERT( nCurrentPos < pNode->Len(), "TransliterateText - String smaller than expected!" ); 3173 pNode->SetChar( nCurrentPos, rNewText.GetChar(n) ); 3174 } 3175 else if ( nDiff < 0 ) 3176 { 3177 // Replace first char, delete the rest... 3178 DBG_ASSERT( nCurrentPos < pNode->Len(), "TransliterateText - String smaller than expected!" ); 3179 pNode->SetChar( nCurrentPos, rNewText.GetChar(n) ); 3180 3181 DBG_ASSERT( (nCurrentPos+1) < pNode->Len(), "TransliterateText - String smaller than expected!" ); 3182 GetEditDoc().RemoveChars( EditPaM( pNode, nCurrentPos+1 ), sal::static_int_cast< sal_uInt16 >(-nDiff) ); 3183 } 3184 else 3185 { 3186 DBG_ASSERT( nDiff == 1, "TransliterateText - Diff other than expected! But should work..." ); 3187 GetEditDoc().InsertText( EditPaM( pNode, nCurrentPos ), rNewText.GetChar(n) ); 3188 3189 } 3190 nDiffs = sal::static_int_cast< short >(nDiffs + nDiff); 3191 } 3192 3193 return nDiffs; 3194 } 3195 3196 3197 void ImpEditEngine::SetAsianCompressionMode( sal_uInt16 n ) 3198 { 3199 if ( n != nAsianCompressionMode ) 3200 { 3201 nAsianCompressionMode = n; 3202 if ( ImplHasText() ) 3203 { 3204 FormatFullDoc(); 3205 UpdateViews(); 3206 } 3207 } 3208 } 3209 3210 void ImpEditEngine::SetKernAsianPunctuation( sal_Bool b ) 3211 { 3212 if ( b != bKernAsianPunctuation ) 3213 { 3214 bKernAsianPunctuation = b; 3215 if ( ImplHasText() ) 3216 { 3217 FormatFullDoc(); 3218 UpdateViews(); 3219 } 3220 } 3221 } 3222 3223 void ImpEditEngine::SetAddExtLeading( sal_Bool bExtLeading ) 3224 { 3225 if ( IsAddExtLeading() != bExtLeading ) 3226 { 3227 bAddExtLeading = bExtLeading; 3228 if ( ImplHasText() ) 3229 { 3230 FormatFullDoc(); 3231 UpdateViews(); 3232 } 3233 } 3234 }; 3235 3236 3237 3238 sal_Bool ImpEditEngine::ImplHasText() const 3239 { 3240 return ( ( GetEditDoc().Count() > 1 ) || GetEditDoc().GetObject(0)->Len() ); 3241 } 3242 3243 long ImpEditEngine::LogicToTwips( long n ) 3244 { 3245 Size aSz( n, 0 ); 3246 MapMode aTwipsMode( MAP_TWIP ); 3247 aSz = pRefDev->LogicToLogic( aSz, NULL, &aTwipsMode ); 3248 return aSz.Width(); 3249 } 3250 3251 3252