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