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# 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 1251 sal_Bool bUsePortionInfo = sal_False; 1252 // sal_Bool bFields = sal_False; 1253 XParaPortionList* pPortionInfo = rTextObject.GetPortionInfo(); 1254 1255 if ( pPortionInfo && ( (long)pPortionInfo->GetPaperWidth() == aPaperSize.Width() ) 1256 && ( pPortionInfo->GetRefMapMode() == GetRefDevice()->GetMapMode() ) ) 1257 { 1258 if ( ( pPortionInfo->GetRefDevPtr() == (sal_uIntPtr)GetRefDevice() ) || 1259 ( ( pPortionInfo->GetRefDevType() == OUTDEV_VIRDEV ) && 1260 ( GetRefDevice()->GetOutDevType() == OUTDEV_VIRDEV ) ) ) 1261 bUsePortionInfo = sal_True; 1262 } 1263 1264 sal_Bool bConvertItems = sal_False; 1265 MapUnit eSourceUnit = MapUnit(), eDestUnit = MapUnit(); 1266 if ( rTextObject.HasMetric() ) 1267 { 1268 eSourceUnit = (MapUnit)rTextObject.GetMetric(); 1269 eDestUnit = (MapUnit)aEditDoc.GetItemPool().GetMetric( DEF_METRIC ); 1270 if ( eSourceUnit != eDestUnit ) 1271 bConvertItems = sal_True; 1272 } 1273 1274 sal_uInt16 nContents = rTextObject.GetContents().Count(); 1275 sal_uInt16 nPara = aEditDoc.GetPos( aPaM.GetNode() ); 1276 1277 for ( sal_uInt16 n = 0; n < nContents; n++, nPara++ ) 1278 { 1279 ContentInfo* pC = rTextObject.GetContents().GetObject( n ); 1280 1281 if ( bIsPasting ) //#115580# 1282 { 1283 if ( !n ) 1284 aPaM = aStart2PaM; 1285 //init node 1286 aPaM.GetNode()->SetStyleSheet( aStart1PaM.GetNode()->GetStyleSheet(), sal_False ); 1287 aPaM.GetNode()->GetContentAttribs().GetItems().ClearItem(); 1288 aPaM.GetNode()->GetCharAttribs().Clear(); 1289 } 1290 1291 sal_Bool bNewContent = aPaM.GetNode()->Len() ? sal_False: sal_True; 1292 sal_uInt16 nStartPos = aPaM.GetIndex(); 1293 1294 aPaM = ImpFastInsertText( aPaM, pC->GetText() ); 1295 1296 ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() ); 1297 DBG_ASSERT( pPortion, "Blinde Portion in FastInsertText" ); 1298 pPortion->MarkInvalid( nStartPos, pC->GetText().Len() ); 1299 1300 // Zeicheattribute... 1301 sal_Bool bAllreadyHasAttribs = aPaM.GetNode()->GetCharAttribs().Count() ? sal_True : sal_False; 1302 sal_uInt16 nNewAttribs = pC->GetAttribs().Count(); 1303 if ( nNewAttribs ) 1304 { 1305 sal_Bool bUpdateFields = sal_False; 1306 for ( sal_uInt16 nAttr = 0; nAttr < nNewAttribs; nAttr++ ) 1307 { 1308 XEditAttribute* pX = pC->GetAttribs().GetObject( nAttr ); 1309 // Kann passieren wenn Absaetze >16K entstehen, dann wird einfach umgebrochen. 1310 if ( pX->GetEnd() <= aPaM.GetNode()->Len() ) 1311 { 1312 if ( !bAllreadyHasAttribs || pX->IsFeature() ) 1313 { 1314 // Normale Attribute gehen dann schneller... 1315 // Features duerfen nicht ueber EditDoc::InsertAttrib 1316 // eingefuegt werden, sie sind bei FastInsertText schon im TextFluss 1317 DBG_ASSERT( pX->GetEnd() <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribut zu gross!" ); 1318 EditCharAttrib* pAttr; 1319 if ( !bConvertItems ) 1320 pAttr = MakeCharAttrib( aEditDoc.GetItemPool(), *(pX->GetItem()), pX->GetStart()+nStartPos, pX->GetEnd()+nStartPos ); 1321 else 1322 { 1323 SfxPoolItem* pNew = pX->GetItem()->Clone(); 1324 ConvertItem( *pNew, eSourceUnit, eDestUnit ); 1325 pAttr = MakeCharAttrib( aEditDoc.GetItemPool(), *pNew, pX->GetStart()+nStartPos, pX->GetEnd()+nStartPos ); 1326 delete pNew; 1327 } 1328 DBG_ASSERT( pAttr->GetEnd() <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribut passt nicht! (1)" ); 1329 aPaM.GetNode()->GetCharAttribs().InsertAttrib( pAttr ); 1330 if ( pAttr->Which() == EE_FEATURE_FIELD ) 1331 bUpdateFields = sal_True; 1332 } 1333 else 1334 { 1335 DBG_ASSERT( pX->GetEnd()+nStartPos <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribut passt nicht! (2)" ); 1336 // Tabs und andere Features koennen nicht ueber InsertAttrib eingefuegt werden: 1337 aEditDoc.InsertAttrib( aPaM.GetNode(), pX->GetStart()+nStartPos, pX->GetEnd()+nStartPos, *pX->GetItem() ); 1338 } 1339 } 1340 } 1341 if ( bUpdateFields ) 1342 UpdateFields(); 1343 1344 // Sonst QuickFormat => Keine Attribute! 1345 pPortion->MarkSelectionInvalid( nStartPos, pC->GetText().Len() ); 1346 } 1347 1348 DBG_ASSERT( CheckOrderedList( aPaM.GetNode()->GetCharAttribs().GetAttribs(), sal_True ), "InsertBinTextObject: Start-Liste verdreht" ); 1349 1350 sal_Bool bParaAttribs = sal_False; 1351 if ( bNewContent || ( ( n > 0 ) && ( n < (nContents-1) ) ) ) 1352 { 1353 bParaAttribs = sal_False; 1354 // #101512# Don't overwrite level/style from existing paragraph in OutlineView 1355 // MT 10/2002: Removed because of #103874#, handled in Outliner::EndPasteOrDropHdl now. 1356 // if ( !aStatus.IsOutliner() || n ) 1357 { 1358 // nur dann Style und ParaAttribs, wenn neuer Absatz, oder 1359 // komplett inneliegender... 1360 bParaAttribs = pC->GetParaAttribs().Count() ? sal_True : sal_False; 1361 1362 if ( bIsPasting ) //#115580# 1363 { 1364 nPara = aEditDoc.GetPos( aPaM.GetNode() ); 1365 if ( GetStyleSheetPool() && pC->GetStyle().Len() ) 1366 { 1367 SfxStyleSheet* pStyle = (SfxStyleSheet*)GetStyleSheetPool()->Find( pC->GetStyle(), pC->GetFamily() ); 1368 DBG_ASSERT( pStyle, "InsertBinTextObject - Style not found!" ); 1369 SetStyleSheet( nPara, pStyle ); 1370 } 1371 } 1372 else 1373 if ( GetStyleSheetPool() && pC->GetStyle().Len() ) 1374 { 1375 SfxStyleSheet* pStyle = (SfxStyleSheet*)GetStyleSheetPool()->Find( pC->GetStyle(), pC->GetFamily() ); 1376 DBG_ASSERT( pStyle, "InsertBinTextObject - Style not found!" ); 1377 SetStyleSheet( nPara, pStyle ); 1378 } 1379 if ( !bConvertItems ) 1380 SetParaAttribs( aEditDoc.GetPos( aPaM.GetNode() ), pC->GetParaAttribs() ); 1381 else 1382 { 1383 SfxItemSet aAttribs( GetEmptyItemSet() ); 1384 ConvertAndPutItems( aAttribs, pC->GetParaAttribs(), &eSourceUnit, &eDestUnit ); 1385 SetParaAttribs( aEditDoc.GetPos( aPaM.GetNode() ), aAttribs ); 1386 } 1387 } 1388 if ( bNewContent && bUsePortionInfo ) 1389 { 1390 XParaPortion* pXP = pPortionInfo->GetObject( n ); 1391 DBG_ASSERT( pXP, "InsertBinTextObject: PortionInfo?" ); 1392 ParaPortion* pParaPortion = GetParaPortions()[ nPara ]; 1393 DBG_ASSERT( pParaPortion, "InsertBinTextObject: ParaPortion?" ); 1394 pParaPortion->nHeight = pXP->nHeight; 1395 pParaPortion->nFirstLineOffset = pXP->nFirstLineOffset; 1396 pParaPortion->bForceRepaint = sal_True; 1397 pParaPortion->SetValid(); // Nicht formatieren 1398 1399 // Die TextPortions 1400 pParaPortion->GetTextPortions().Reset(); 1401 sal_uInt16 nCount = pXP->aTextPortions.Count(); 1402 for ( sal_uInt16 _n = 0; _n < nCount; _n++ ) 1403 { 1404 TextPortion* pTextPortion = pXP->aTextPortions[_n]; 1405 TextPortion* pNew = new TextPortion( *pTextPortion ); 1406 pParaPortion->GetTextPortions().Insert( pNew, _n ); 1407 } 1408 1409 // Die Zeilen 1410 pParaPortion->GetLines().Reset(); 1411 nCount = pXP->aLines.Count(); 1412 for ( sal_uInt16 m = 0; m < nCount; m++ ) 1413 { 1414 EditLine* pLine = pXP->aLines[m]; 1415 EditLine* pNew = pLine->Clone(); 1416 pNew->SetInvalid(); // neu Painten! 1417 pParaPortion->GetLines().Insert( pNew, m ); 1418 } 1419 #ifdef DBG_UTIL 1420 sal_uInt16 nTest; 1421 int nTPLen = 0, nTxtLen = 0; 1422 for ( nTest = pParaPortion->GetTextPortions().Count(); nTest; ) 1423 nTPLen += pParaPortion->GetTextPortions().GetObject( --nTest )->GetLen(); 1424 for ( nTest = pParaPortion->GetLines().Count(); nTest; ) 1425 nTxtLen += pParaPortion->GetLines().GetObject( --nTest )->GetLen(); 1426 DBG_ASSERT( ( nTPLen == pParaPortion->GetNode()->Len() ) && ( nTxtLen == pParaPortion->GetNode()->Len() ), "InsertBinTextObject: ParaPortion not completely formatted!" ); 1427 #endif 1428 } 1429 } 1430 if ( !bParaAttribs ) // DefFont wird bei FastInsertParagraph nicht berechnet 1431 { 1432 aPaM.GetNode()->GetCharAttribs().GetDefFont() = aEditDoc.GetDefFont(); 1433 if ( aStatus.UseCharAttribs() ) 1434 aPaM.GetNode()->CreateDefFont(); 1435 } 1436 1437 #ifndef SVX_LIGHT 1438 if ( bNewContent && GetStatus().DoOnlineSpelling() && pC->GetWrongList() ) 1439 { 1440 aPaM.GetNode()->DestroyWrongList(); // otherwise MLK, if list exists... 1441 aPaM.GetNode()->SetWrongList( pC->GetWrongList()->Clone() ); 1442 } 1443 #endif // !SVX_LIGHT 1444 1445 if ( bIsPasting ) //#115580# 1446 { 1447 AdjustParaAttribsByStyleSheet( aPaM.GetNode() ); 1448 ParaAttribsToCharAttribs( aPaM.GetNode() ); 1449 } 1450 1451 // Zeilenumbruch, wenn weitere folgen... 1452 if ( n < ( nContents-1) ) 1453 { 1454 if ( bNewContent ) 1455 aPaM = ImpFastInsertParagraph( nPara+1 ); 1456 else 1457 aPaM = ImpInsertParaBreak( aPaM, sal_False ); 1458 } 1459 } 1460 1461 /* aSel.Max() = aPaM; */ //#115580# 1462 1463 if ( bIsPasting ) 1464 { 1465 EditPaM aEnd2PaM( aPaM ); 1466 1467 sal_Bool bSpecialBackward = aStart1PaM.GetNode()->Len() ? sal_False : sal_True; 1468 1469 aSel.Min() = ImpConnectParagraphs( aStart1PaM.GetNode(), aStart2PaM.GetNode(), bSpecialBackward ); 1470 bSpecialBackward = aEnd1PaM.GetNode()->Len() ? sal_True : sal_False; 1471 1472 aSel.Max() = ImpConnectParagraphs( ( ( nContents == 1 ) ? aStart1PaM.GetNode() : aEnd2PaM.GetNode() ), 1473 aEnd1PaM.GetNode(), bSpecialBackward ); 1474 } 1475 else 1476 aSel.Max() = aPaM; 1477 1478 DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "InsertBibTextObject: Selektion kaput!(1)" ); 1479 return aSel; 1480 } 1481 1482 LanguageType ImpEditEngine::GetLanguage( const EditPaM& rPaM, sal_uInt16* pEndPos ) const 1483 { 1484 short nScriptType = GetScriptType( rPaM, pEndPos ); // pEndPos will be valid now, pointing to ScriptChange or NodeLen 1485 sal_uInt16 nLangId = GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ); 1486 const SvxLanguageItem* pLangItem = &(const SvxLanguageItem&)rPaM.GetNode()->GetContentAttribs().GetItem( nLangId ); 1487 EditCharAttrib* pAttr = rPaM.GetNode()->GetCharAttribs().FindAttrib( nLangId, rPaM.GetIndex() ); 1488 if ( pAttr ) 1489 pLangItem = (const SvxLanguageItem*)pAttr->GetItem(); 1490 1491 if ( pEndPos && pAttr && ( pAttr->GetEnd() < *pEndPos ) ) 1492 *pEndPos = pAttr->GetEnd(); 1493 1494 return pLangItem->GetLanguage(); 1495 } 1496 1497 ::com::sun::star::lang::Locale ImpEditEngine::GetLocale( const EditPaM& rPaM ) const 1498 { 1499 return SvxCreateLocale( GetLanguage( rPaM ) ); 1500 } 1501 1502 Reference< XSpellChecker1 > ImpEditEngine::GetSpeller() 1503 { 1504 #ifndef SVX_LIGHT 1505 if ( !xSpeller.is() ) 1506 xSpeller = SvxGetSpellChecker(); 1507 #endif 1508 return xSpeller; 1509 } 1510 1511 1512 SpellInfo * ImpEditEngine::CreateSpellInfo( const EditSelection &rSel, bool bMultipleDocs ) 1513 { 1514 if (!pSpellInfo) 1515 pSpellInfo = new SpellInfo; 1516 else 1517 *pSpellInfo = SpellInfo(); // reset to default values 1518 1519 pSpellInfo->bMultipleDoc = bMultipleDocs; 1520 EditSelection aSentenceSel( SelectSentence( rSel ) ); 1521 // pSpellInfo->aSpellStart = CreateEPaM( aSentenceSel.Min() ); 1522 // pSpellInfo->aSpellTo = CreateEPaM( rSel.HasRange()? aSentenceSel.Max() : aSentenceSel.Min() ); 1523 // always spell draw objects completely, startting at the top. 1524 // (spelling in only a selection or not starting with the top requires 1525 // further changes elsewehe to work properly) 1526 pSpellInfo->aSpellStart = EPaM(); 1527 pSpellInfo->aSpellTo = EPaM( EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND ); 1528 return pSpellInfo; 1529 } 1530 1531 1532 EESpellState ImpEditEngine::Spell( EditView* pEditView, sal_Bool bMultipleDoc ) 1533 { 1534 #ifdef SVX_LIGHT 1535 return EE_SPELL_NOSPELLER; 1536 #else 1537 1538 DBG_ASSERTWARNING( xSpeller.is(), "Kein Speller gesetzt!" ); 1539 1540 if ( !xSpeller.is() ) 1541 return EE_SPELL_NOSPELLER; 1542 1543 aOnlineSpellTimer.Stop(); 1544 1545 // Bei MultipleDoc immer von vorne/hinten... 1546 if ( bMultipleDoc ) 1547 { 1548 pEditView->pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); 1549 } 1550 1551 EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); 1552 pSpellInfo = CreateSpellInfo( aCurSel, bMultipleDoc ); 1553 1554 sal_Bool bIsStart = sal_False; 1555 if ( bMultipleDoc ) 1556 bIsStart = sal_True; // Immer von Vorne bzw. von hinten... 1557 else if ( ( CreateEPaM( aEditDoc.GetStartPaM() ) == pSpellInfo->aSpellStart ) ) 1558 bIsStart = sal_True; 1559 1560 EditSpellWrapper* pWrp = new EditSpellWrapper( Application::GetDefDialogParent(), 1561 xSpeller, bIsStart, sal_False, pEditView ); 1562 pWrp->SpellDocument(); 1563 delete pWrp; 1564 1565 if ( !bMultipleDoc ) 1566 { 1567 pEditView->pImpEditView->DrawSelection(); 1568 if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() ) 1569 aCurSel.Max().GetIndex() = aCurSel.Max().GetNode()->Len(); 1570 aCurSel.Min() = aCurSel.Max(); 1571 pEditView->pImpEditView->SetEditSelection( aCurSel ); 1572 pEditView->pImpEditView->DrawSelection(); 1573 pEditView->ShowCursor( sal_True, sal_False ); 1574 } 1575 EESpellState eState = pSpellInfo->eState; 1576 delete pSpellInfo; 1577 pSpellInfo = 0; 1578 return eState; 1579 #endif 1580 } 1581 1582 1583 sal_Bool ImpEditEngine::HasConvertibleTextPortion( LanguageType nSrcLang ) 1584 { 1585 #ifdef SVX_LIGHT 1586 return sal_False; 1587 #else 1588 sal_Bool bHasConvTxt = sal_False; 1589 1590 sal_uInt16 nParas = pEditEngine->GetParagraphCount(); 1591 for (sal_uInt16 k = 0; k < nParas; ++k) 1592 { 1593 SvUShorts aPortions; 1594 pEditEngine->GetPortions( k, aPortions ); 1595 for ( sal_uInt16 nPos = 0; nPos < aPortions.Count(); ++nPos ) 1596 { 1597 sal_uInt16 nEnd = aPortions.GetObject( nPos ); 1598 sal_uInt16 nStart = nPos > 0 ? aPortions.GetObject( nPos - 1 ) : 0; 1599 1600 // if the paragraph is not empty we need to increase the index 1601 // by one since the attribute of the character left to the 1602 // specified position is evaluated. 1603 if (nEnd > nStart) // empty para? 1604 ++nStart; 1605 LanguageType nLangFound = pEditEngine->GetLanguage( k, nStart ); 1606 #ifdef DEBUG 1607 lang::Locale aLocale( SvxCreateLocale( nLangFound ) ); 1608 #endif 1609 bHasConvTxt = (nSrcLang == nLangFound) || 1610 (editeng::HangulHanjaConversion::IsChinese( nLangFound ) && 1611 editeng::HangulHanjaConversion::IsChinese( nSrcLang )); 1612 if (bHasConvTxt) 1613 return bHasConvTxt; 1614 } 1615 } 1616 1617 #endif 1618 return bHasConvTxt; 1619 } 1620 1621 1622 void ImpEditEngine::Convert( EditView* pEditView, 1623 LanguageType nSrcLang, LanguageType nDestLang, const Font *pDestFont, 1624 sal_Int32 nOptions, sal_Bool bIsInteractive, sal_Bool bMultipleDoc ) 1625 { 1626 // modified version of ImpEditEngine::Spell 1627 1628 #ifdef SVX_LIGHT 1629 #else 1630 1631 // Bei MultipleDoc immer von vorne/hinten... 1632 if ( bMultipleDoc ) 1633 pEditView->pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); 1634 1635 // 1636 // initialize pConvInfo 1637 // 1638 EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); 1639 aCurSel.Adjust( aEditDoc ); 1640 pConvInfo = new ConvInfo; 1641 pConvInfo->bMultipleDoc = bMultipleDoc; 1642 pConvInfo->aConvStart = CreateEPaM( aCurSel.Min() ); 1643 // 1644 // if it is not just a selection and we are about to begin 1645 // with the current conversion for the very first time 1646 // we need to find the start of the current (initial) 1647 // convertible unit in order for the text conversion to give 1648 // the correct result for that. Since it is easier to obtain 1649 // the start of the word we use that though. 1650 if (!aCurSel.HasRange() && ImplGetBreakIterator().is()) 1651 { 1652 EditPaM aWordStartPaM( SelectWord( aCurSel, i18n::WordType::DICTIONARY_WORD ).Min() ); 1653 1654 // since #118246 / #117803 still occurs if the cursor is placed 1655 // between the two chinese characters to be converted (because both 1656 // of them are words on their own!) using the word boundary here does 1657 // not work. Thus since chinese conversion is not interactive we start 1658 // at the begin of the paragraph to solve the problem, i.e. have the 1659 // TextConversion service get those characters together in the same call. 1660 sal_uInt16 nStartIdx = ( editeng::HangulHanjaConversion::IsChinese( nSrcLang ) ) ? 1661 0 : aWordStartPaM.GetIndex(); 1662 pConvInfo->aConvStart.nIndex = nStartIdx; 1663 } 1664 // 1665 pConvInfo->aConvContinue = pConvInfo->aConvStart; 1666 1667 sal_Bool bIsStart = sal_False; 1668 if ( bMultipleDoc ) 1669 bIsStart = sal_True; // Immer von Vorne bzw. von hinten... 1670 else if ( CreateEPaM( aEditDoc.GetStartPaM() ) == pConvInfo->aConvStart ) 1671 bIsStart = sal_True; 1672 1673 bImpConvertFirstCall = sal_True; // next ImpConvert call is the very first in this conversion turn 1674 1675 Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); 1676 TextConvWrapper aWrp( Application::GetDefDialogParent(), xMSF, 1677 SvxCreateLocale( nSrcLang ), SvxCreateLocale( nDestLang ), 1678 pDestFont, 1679 nOptions, bIsInteractive, 1680 bIsStart, pEditView ); 1681 1682 // 1683 //!! optimization does not work since when update mode is false 1684 //!! the object is 'lying' about it portions, paragraphs, 1685 //!! EndPaM... later on. 1686 //!! Should not be a great problem since text boxes or cells in 1687 //!! Calc usually have only a rather short text. 1688 // 1689 // disallow formatting, updating the view, ... while 1690 // non-interactively converting the document. (saves time) 1691 //if (!bIsInteractive) 1692 // SetUpdateMode( sal_False ); 1693 1694 aWrp.Convert(); 1695 1696 //if (!bIsInteractive) 1697 //SetUpdateMode( sal_True, 0, sal_True ); 1698 1699 if ( !bMultipleDoc ) 1700 { 1701 pEditView->pImpEditView->DrawSelection(); 1702 if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() ) 1703 aCurSel.Max().GetIndex() = aCurSel.Max().GetNode()->Len(); 1704 aCurSel.Min() = aCurSel.Max(); 1705 pEditView->pImpEditView->SetEditSelection( aCurSel ); 1706 pEditView->pImpEditView->DrawSelection(); 1707 pEditView->ShowCursor( sal_True, sal_False ); 1708 } 1709 delete pConvInfo; 1710 pConvInfo = 0; 1711 #endif 1712 } 1713 1714 1715 void ImpEditEngine::SetLanguageAndFont( 1716 const ESelection &rESel, 1717 LanguageType nLang, sal_uInt16 nLangWhichId, 1718 const Font *pFont, sal_uInt16 nFontWhichId ) 1719 { 1720 ESelection aOldSel = pActiveView->GetSelection(); 1721 pActiveView->SetSelection( rESel ); 1722 1723 // set new language attribute 1724 SfxItemSet aNewSet( pActiveView->GetEmptyItemSet() ); 1725 aNewSet.Put( SvxLanguageItem( nLang, nLangWhichId ) ); 1726 1727 // new font to be set? 1728 DBG_ASSERT( pFont, "target font missing?" ); 1729 if (pFont) 1730 { 1731 // set new font attribute 1732 SvxFontItem aFontItem = (SvxFontItem&) aNewSet.Get( nFontWhichId ); 1733 aFontItem.SetFamilyName( pFont->GetName()); 1734 aFontItem.SetFamily( pFont->GetFamily()); 1735 aFontItem.SetStyleName( pFont->GetStyleName()); 1736 aFontItem.SetPitch( pFont->GetPitch()); 1737 aFontItem.SetCharSet( pFont->GetCharSet() ); 1738 aNewSet.Put( aFontItem ); 1739 } 1740 1741 // apply new attributes 1742 pActiveView->SetAttribs( aNewSet ); 1743 1744 pActiveView->SetSelection( aOldSel ); 1745 } 1746 1747 1748 void ImpEditEngine::ImpConvert( rtl::OUString &rConvTxt, LanguageType &rConvTxtLang, 1749 EditView* pEditView, LanguageType nSrcLang, const ESelection &rConvRange, 1750 sal_Bool bAllowImplicitChangesForNotConvertibleText, 1751 LanguageType nTargetLang, const Font *pTargetFont ) 1752 { 1753 // modified version of ImpEditEngine::ImpSpell 1754 1755 // looks for next convertible text portion to be passed on to the wrapper 1756 1757 String aRes; 1758 LanguageType nResLang = LANGUAGE_NONE; 1759 1760 #ifdef SVX_LIGHT 1761 rConvTxt = rtl::OUString(); 1762 rConvTxtLang = LANGUAGE_NONE; 1763 #else 1764 1765 /* ContentNode* pLastNode = */ aEditDoc.SaveGetObject( aEditDoc.Count()-1 ); 1766 1767 EditPaM aPos( CreateEditPaM( pConvInfo->aConvContinue ) ); 1768 EditSelection aCurSel = EditSelection( aPos, aPos ); 1769 1770 String aWord; 1771 1772 while (!aRes.Len()) 1773 { 1774 // empty paragraph found that needs to have language and font set? 1775 if (bAllowImplicitChangesForNotConvertibleText && 1776 !pEditEngine->GetText( pConvInfo->aConvContinue.nPara ).Len()) 1777 { 1778 sal_uInt16 nPara = pConvInfo->aConvContinue.nPara; 1779 ESelection aESel( nPara, 0, nPara, 0 ); 1780 // see comment for below same function call 1781 SetLanguageAndFont( aESel, 1782 nTargetLang, EE_CHAR_LANGUAGE_CJK, 1783 pTargetFont, EE_CHAR_FONTINFO_CJK ); 1784 } 1785 1786 1787 if (pConvInfo->aConvContinue.nPara == pConvInfo->aConvTo.nPara && 1788 pConvInfo->aConvContinue.nIndex >= pConvInfo->aConvTo.nIndex) 1789 break; 1790 1791 /* 1792 // Bekannter (wahrscheinlicher) Bug: Wenn SpellToCurrent, muss 1793 // Current bei jeder Ersetzung korrigiert werden, sonst passt 1794 // das Ende evtl. nicht mehr genau... 1795 if ( pConvInfo->bConvToEnd || pConvInfo->bMultipleDoc ) 1796 { 1797 if ( aCurSel.Max().GetNode() == pLastNode && 1798 aCurSel.Max().GetIndex() >= pLastNode->Len() ) 1799 break; 1800 } 1801 */ 1802 1803 sal_uInt16 nAttribStart = USHRT_MAX; 1804 sal_uInt16 nAttribEnd = USHRT_MAX; 1805 sal_uInt16 nCurPos = USHRT_MAX; 1806 EPaM aCurStart = CreateEPaM( aCurSel.Min() ); 1807 SvUShorts aPortions; 1808 pEditEngine->GetPortions( (sal_uInt16)aCurStart.nPara, aPortions ); 1809 for ( sal_uInt16 nPos = 0; nPos < aPortions.Count(); ++nPos ) 1810 { 1811 sal_uInt16 nEnd = aPortions.GetObject( nPos ); 1812 sal_uInt16 nStart = nPos > 0 ? aPortions.GetObject( nPos - 1 ) : 0; 1813 1814 // the language attribute is obtained from the left character 1815 // (like usually all other attributes) 1816 // thus we usually have to add 1 in order to get the language 1817 // of the text right to the cursor position 1818 sal_uInt16 nLangIdx = nEnd > nStart ? nStart + 1 : nStart; 1819 LanguageType nLangFound = pEditEngine->GetLanguage( aCurStart.nPara, nLangIdx ); 1820 #ifdef DEBUG 1821 lang::Locale aLocale( SvxCreateLocale( nLangFound ) ); 1822 #endif 1823 sal_Bool bLangOk = (nLangFound == nSrcLang) || 1824 (editeng::HangulHanjaConversion::IsChinese( nLangFound ) && 1825 editeng::HangulHanjaConversion::IsChinese( nSrcLang )); 1826 1827 if (nAttribEnd != USHRT_MAX) // start already found? 1828 { 1829 DBG_ASSERT(nEnd >= aCurStart.nIndex, "error while scanning attributes (a)" ); 1830 DBG_ASSERT(nEnd >= nAttribEnd, "error while scanning attributes (b)" ); 1831 if (/*nEnd >= aCurStart.nIndex &&*/ nLangFound == nResLang) 1832 nAttribEnd = nEnd; 1833 else // language attrib has changed 1834 break; 1835 } 1836 if (nAttribStart == USHRT_MAX && // start not yet found? 1837 nEnd > aCurStart.nIndex && bLangOk) 1838 { 1839 nAttribStart = nStart; 1840 nAttribEnd = nEnd; 1841 nResLang = nLangFound; 1842 } 1843 //! the list of portions may have changed compared to the previous 1844 //! call to this function (because of possibly changed language 1845 //! attribute!) 1846 //! But since we don't want to start in the already processed part 1847 //! we clip the start accordingly. 1848 if (nAttribStart < aCurStart.nIndex) 1849 { 1850 nAttribStart = aCurStart.nIndex; 1851 } 1852 1853 // check script type to the right of the start of the current portion 1854 EditPaM aPaM( CreateEditPaM( EPaM(aCurStart.nPara, nLangIdx) ) ); 1855 sal_Bool bIsAsianScript = (i18n::ScriptType::ASIAN == GetScriptType( aPaM )); 1856 // not yet processed text part with for conversion 1857 // not suitable language found that needs to be changed? 1858 if (bAllowImplicitChangesForNotConvertibleText && 1859 !bLangOk && !bIsAsianScript && nEnd > aCurStart.nIndex) 1860 { 1861 ESelection aESel( aCurStart.nPara, nStart, aCurStart.nPara, nEnd ); 1862 // set language and font to target language and font of conversion 1863 //! Now this especially includes all non convertible text e.g. 1864 //! spaces, empty paragraphs and western text. 1865 // This is in order for every *new* text entered at *any* position to 1866 // have the correct language and font attributes set. 1867 SetLanguageAndFont( aESel, 1868 nTargetLang, EE_CHAR_LANGUAGE_CJK, 1869 pTargetFont, EE_CHAR_FONTINFO_CJK ); 1870 } 1871 1872 nCurPos = nEnd; 1873 } 1874 1875 if (nAttribStart != USHRT_MAX && nAttribEnd != USHRT_MAX) 1876 { 1877 aCurSel.Min().SetIndex( nAttribStart ); 1878 aCurSel.Max().SetIndex( nAttribEnd ); 1879 } 1880 else if (nCurPos != USHRT_MAX) 1881 { 1882 // set selection to end of scanned text 1883 // (used to set the position where to continue from later on) 1884 aCurSel.Min().SetIndex( nCurPos ); 1885 aCurSel.Max().SetIndex( nCurPos ); 1886 } 1887 1888 if ( !pConvInfo->bConvToEnd ) 1889 { 1890 EPaM aEPaM( CreateEPaM( aCurSel.Min() ) ); 1891 if ( !( aEPaM < pConvInfo->aConvTo ) ) 1892 break; 1893 } 1894 1895 // clip selected word to the converted area 1896 // (main use when conversion starts/ends **within** a word) 1897 EditPaM aPaM( CreateEditPaM( pConvInfo->aConvStart ) ); 1898 if (pConvInfo->bConvToEnd && 1899 aCurSel.Min().GetNode() == aPaM.GetNode() && 1900 aCurSel.Min().GetIndex() < aPaM.GetIndex()) 1901 aCurSel.Min().SetIndex( aPaM.GetIndex() ); 1902 aPaM = CreateEditPaM( pConvInfo->aConvContinue ); 1903 if (aCurSel.Min().GetNode() == aPaM.GetNode() && 1904 aCurSel.Min().GetIndex() < aPaM.GetIndex()) 1905 aCurSel.Min().SetIndex( aPaM.GetIndex() ); 1906 aPaM = CreateEditPaM( pConvInfo->aConvTo ); 1907 if ((!pConvInfo->bConvToEnd || rConvRange.HasRange())&& 1908 aCurSel.Max().GetNode() == aPaM.GetNode() && 1909 aCurSel.Max().GetIndex() > aPaM.GetIndex()) 1910 aCurSel.Max().SetIndex( aPaM.GetIndex() ); 1911 1912 aWord = GetSelected( aCurSel ); 1913 1914 if ( aWord.Len() > 0 /* && bLangOk */) 1915 aRes = aWord; 1916 1917 // move to next word/paragraph if necessary 1918 if ( !aRes.Len() ) 1919 aCurSel = WordRight( aCurSel.Min(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 1920 1921 pConvInfo->aConvContinue = CreateEPaM( aCurSel.Max() ); 1922 } 1923 1924 pEditView->pImpEditView->DrawSelection(); 1925 pEditView->pImpEditView->SetEditSelection( aCurSel ); 1926 pEditView->pImpEditView->DrawSelection(); 1927 pEditView->ShowCursor( sal_True, sal_False ); 1928 1929 rConvTxt = aRes; 1930 if (rConvTxt.getLength()) 1931 rConvTxtLang = nResLang; 1932 #endif 1933 } 1934 1935 1936 Reference< XSpellAlternatives > ImpEditEngine::ImpSpell( EditView* pEditView ) 1937 { 1938 #ifdef SVX_LIGHT 1939 return Reference< XSpellAlternatives >(); 1940 #else 1941 1942 DBG_ASSERT( xSpeller.is(), "Kein Speller gesetzt!" ); 1943 1944 ContentNode* pLastNode = aEditDoc.SaveGetObject( (aEditDoc.Count()-1) ); 1945 EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); 1946 aCurSel.Min() = aCurSel.Max(); 1947 1948 String aWord; 1949 Reference< XSpellAlternatives > xSpellAlt; 1950 Sequence< PropertyValue > aEmptySeq; 1951 while (!xSpellAlt.is()) 1952 { 1953 1954 // Bekannter (wahrscheinlicher) Bug: Wenn SpellToCurrent, muss 1955 // Current bei jeder Ersetzung korrigiert werden, sonst passt 1956 // das Ende evtl. nicht mehr genau... 1957 if ( pSpellInfo->bSpellToEnd || pSpellInfo->bMultipleDoc ) 1958 { 1959 if ( aCurSel.Max().GetNode() == pLastNode ) 1960 { 1961 if ( ( aCurSel.Max().GetIndex() >= pLastNode->Len() ) ) 1962 break; 1963 } 1964 } 1965 else if ( !pSpellInfo->bSpellToEnd ) 1966 { 1967 EPaM aEPaM( CreateEPaM( aCurSel.Max() ) ); 1968 if ( !( aEPaM < pSpellInfo->aSpellTo ) ) 1969 break; 1970 } 1971 1972 aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 1973 aWord = GetSelected( aCurSel ); 1974 1975 // Wenn Punkt dahinter, muss dieser mit uebergeben werden ! 1976 // Falls Abkuerzung... 1977 if ( aWord.Len() && ( aCurSel.Max().GetIndex() < aCurSel.Max().GetNode()->Len() ) ) 1978 { 1979 sal_Unicode cNext = aCurSel.Max().GetNode()->GetChar( aCurSel.Max().GetIndex() ); 1980 if ( cNext == '.' ) 1981 { 1982 aCurSel.Max().GetIndex()++; 1983 aWord += cNext; 1984 } 1985 } 1986 1987 if ( aWord.Len() > 0 ) 1988 { 1989 LanguageType eLang = GetLanguage( aCurSel.Max() ); 1990 SvxSpellWrapper::CheckSpellLang( xSpeller, eLang ); 1991 xSpellAlt = xSpeller->spell( aWord, eLang, aEmptySeq ); 1992 } 1993 1994 if ( !xSpellAlt.is() ) 1995 aCurSel = WordRight( aCurSel.Min(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 1996 else 1997 pSpellInfo->eState = EE_SPELL_ERRORFOUND; 1998 } 1999 2000 pEditView->pImpEditView->DrawSelection(); 2001 pEditView->pImpEditView->SetEditSelection( aCurSel ); 2002 pEditView->pImpEditView->DrawSelection(); 2003 pEditView->ShowCursor( sal_True, sal_False ); 2004 return xSpellAlt; 2005 #endif 2006 } 2007 /*-- 13.10.2003 16:43:27--------------------------------------------------- 2008 2009 -----------------------------------------------------------------------*/ 2010 void ImpEditEngine::EndSpelling() 2011 { 2012 DELETEZ(pSpellInfo); 2013 } 2014 /*-- 13.10.2003 16:43:27--------------------------------------------------- 2015 2016 -----------------------------------------------------------------------*/ 2017 void ImpEditEngine::StartSpelling(EditView& rEditView, sal_Bool bMultipleDoc) 2018 { 2019 DBG_ASSERT(!pSpellInfo, "pSpellInfo already set?"); 2020 rEditView.pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); 2021 EditSelection aCurSel( rEditView.pImpEditView->GetEditSelection() ); 2022 pSpellInfo = CreateSpellInfo( aCurSel, bMultipleDoc ); 2023 } 2024 /*-- 13.10.2003 16:43:27--------------------------------------------------- 2025 Search for the next wrong word within the given selection 2026 -----------------------------------------------------------------------*/ 2027 Reference< XSpellAlternatives > ImpEditEngine::ImpFindNextError(EditSelection& rSelection) 2028 { 2029 /* ContentNode* pLastNode = */ aEditDoc.SaveGetObject( (aEditDoc.Count()-1) ); 2030 EditSelection aCurSel( rSelection.Min() ); 2031 2032 String aWord; 2033 Reference< XSpellAlternatives > xSpellAlt; 2034 Sequence< PropertyValue > aEmptySeq; 2035 while (!xSpellAlt.is()) 2036 { 2037 //check if the end of the selection has been reached 2038 { 2039 EPaM aEPaM( CreateEPaM( aCurSel.Max() ) ); 2040 if ( !( aEPaM < CreateEPaM( rSelection.Max()) ) ) 2041 break; 2042 } 2043 2044 aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 2045 aWord = GetSelected( aCurSel ); 2046 2047 // Wenn Punkt dahinter, muss dieser mit uebergeben werden ! 2048 // Falls Abkuerzung... 2049 if ( aWord.Len() && ( aCurSel.Max().GetIndex() < aCurSel.Max().GetNode()->Len() ) ) 2050 { 2051 sal_Unicode cNext = aCurSel.Max().GetNode()->GetChar( aCurSel.Max().GetIndex() ); 2052 if ( cNext == '.' ) 2053 { 2054 aCurSel.Max().GetIndex()++; 2055 aWord += cNext; 2056 } 2057 } 2058 2059 if ( aWord.Len() > 0 ) 2060 xSpellAlt = xSpeller->spell( aWord, GetLanguage( aCurSel.Max() ), aEmptySeq ); 2061 2062 if ( !xSpellAlt.is() ) 2063 aCurSel = WordRight( aCurSel.Min(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 2064 else 2065 { 2066 pSpellInfo->eState = EE_SPELL_ERRORFOUND; 2067 rSelection = aCurSel; 2068 } 2069 } 2070 return xSpellAlt; 2071 } 2072 /*-- 13.10.2003 16:43:27--------------------------------------------------- 2073 2074 -----------------------------------------------------------------------*/ 2075 bool ImpEditEngine::SpellSentence(EditView& rEditView, 2076 ::svx::SpellPortions& rToFill, 2077 bool /*bIsGrammarChecking*/ ) 2078 { 2079 #ifdef SVX_LIGHT 2080 #else 2081 bool bRet = false; 2082 EditSelection aCurSel( rEditView.pImpEditView->GetEditSelection() ); 2083 if(!pSpellInfo) 2084 pSpellInfo = CreateSpellInfo( aCurSel, true ); 2085 pSpellInfo->aCurSentenceStart = aCurSel.Min(); 2086 DBG_ASSERT( xSpeller.is(), "Kein Speller gesetzt!" ); 2087 pSpellInfo->aLastSpellPortions.clear(); 2088 pSpellInfo->aLastSpellContentSelections.clear(); 2089 rToFill.clear(); 2090 //if no selection previously exists the range is extended to the end of the object 2091 if(aCurSel.Min() == aCurSel.Max()) 2092 { 2093 ContentNode* pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count()-1); 2094 aCurSel.Max() = EditPaM(pLastNode, pLastNode->Len()); 2095 } 2096 // check for next error in aCurSel and set aCurSel to that one if any was found 2097 Reference< XSpellAlternatives > xAlt = ImpFindNextError(aCurSel); 2098 if (xAlt.is()) 2099 { 2100 bRet = true; 2101 //find the sentence boundaries 2102 EditSelection aSentencePaM = SelectSentence(aCurSel); 2103 //make sure that the sentence is never smaller than the error range! 2104 if(aSentencePaM.Max().GetIndex() < aCurSel.Max().GetIndex()) 2105 aSentencePaM.Max() = aCurSel.Max(); 2106 //add the portion preceeding the error 2107 EditSelection aStartSelection(aSentencePaM.Min(), aCurSel.Min()); 2108 if(aStartSelection.HasRange()) 2109 AddPortionIterated(rEditView, aStartSelection, 0, rToFill); 2110 //add the error portion 2111 AddPortionIterated(rEditView, aCurSel, xAlt, rToFill); 2112 //find the end of the sentence 2113 //search for all errors in the rest of the sentence and add all the portions 2114 do 2115 { 2116 EditSelection aNextSel = EditSelection(aCurSel.Max(), aSentencePaM.Max()); 2117 xAlt = ImpFindNextError(aNextSel); 2118 if(xAlt.is()) 2119 { 2120 //add the part between the previous and the current error 2121 AddPortionIterated(rEditView, EditSelection(aCurSel.Max(), aNextSel.Min()), 0, rToFill); 2122 //add the current error 2123 AddPortionIterated(rEditView, aNextSel, xAlt, rToFill); 2124 } 2125 else 2126 AddPortionIterated(rEditView, EditSelection(aCurSel.Max(), aSentencePaM.Max()), xAlt, rToFill); 2127 aCurSel = aNextSel; 2128 } 2129 while( xAlt.is() ); 2130 2131 //set the selection to the end of the current sentence 2132 rEditView.pImpEditView->SetEditSelection(aSentencePaM.Max()); 2133 } 2134 #endif 2135 return bRet; 2136 } 2137 2138 /*-- 15.10.2003 16:09:12--------------------------------------------------- 2139 adds one portion to the SpellPortions 2140 -----------------------------------------------------------------------*/ 2141 void ImpEditEngine::AddPortion( 2142 const EditSelection rSel, 2143 uno::Reference< XSpellAlternatives > xAlt, 2144 ::svx::SpellPortions& rToFill, 2145 bool bIsField) 2146 { 2147 #ifdef SVX_LIGHT 2148 #else 2149 if(rSel.HasRange()) 2150 { 2151 svx::SpellPortion aPortion; 2152 aPortion.sText = GetSelected( rSel ); 2153 aPortion.eLanguage = GetLanguage( rSel.Min() ); 2154 aPortion.xAlternatives = xAlt; 2155 aPortion.bIsField = bIsField; 2156 rToFill.push_back(aPortion); 2157 2158 //save the spelled portions for later use 2159 pSpellInfo->aLastSpellPortions.push_back(aPortion); 2160 pSpellInfo->aLastSpellContentSelections.push_back(rSel); 2161 2162 } 2163 #endif 2164 } 2165 2166 /*-- 15.10.2003 16:07:47--------------------------------------------------- 2167 adds one or more portions of text to the SpellPortions depending on language changes 2168 -----------------------------------------------------------------------*/ 2169 void ImpEditEngine::AddPortionIterated( 2170 EditView& rEditView, 2171 const EditSelection rSel, 2172 Reference< XSpellAlternatives > xAlt, 2173 ::svx::SpellPortions& rToFill) 2174 { 2175 #ifdef SVX_LIGHT 2176 #else 2177 if(rSel.Min() != rSel.Max()) 2178 { 2179 if(xAlt.is()) 2180 { 2181 AddPortion(rSel, xAlt, rToFill, false); 2182 } 2183 else 2184 { 2185 //iterate and search for language attribute changes 2186 //save the start and end positions 2187 bool bTest = rSel.Min().GetIndex() <= rSel.Max().GetIndex(); 2188 EditPaM aStart(bTest ? rSel.Min() : rSel.Max()); 2189 EditPaM aEnd(bTest ? rSel.Max() : rSel.Min()); 2190 //iterate over the text to find changes in language 2191 //set the mark equal to the point 2192 EditPaM aCursor(aStart); 2193 rEditView.pImpEditView->SetEditSelection( aCursor ); 2194 LanguageType eStartLanguage = GetLanguage( aCursor ); 2195 //search for a field attribute at the beginning - only the end position 2196 //of this field is kept to end a portion at that position 2197 const EditCharAttrib* pFieldAttr = aCursor.GetNode()->GetCharAttribs(). 2198 FindFeature( aCursor.GetIndex() ); 2199 bool bIsField = pFieldAttr && 2200 pFieldAttr->GetStart() == aCursor.GetIndex() && 2201 pFieldAttr->GetStart() != pFieldAttr->GetEnd() && 2202 pFieldAttr->Which() == EE_FEATURE_FIELD; 2203 sal_uInt16 nEndField = bIsField ? pFieldAttr->GetEnd() : USHRT_MAX; 2204 bool bIsEndField = false; 2205 do 2206 { 2207 aCursor = CursorRight( aCursor); 2208 //determine whether a field and has been reached 2209 bIsEndField = nEndField == aCursor.GetIndex(); 2210 //search for a new field attribute 2211 EditCharAttrib* _pFieldAttr = aCursor.GetNode()->GetCharAttribs(). 2212 FindFeature( aCursor.GetIndex() ); 2213 bIsField = _pFieldAttr && 2214 _pFieldAttr->GetStart() == aCursor.GetIndex() && 2215 _pFieldAttr->GetStart() != _pFieldAttr->GetEnd() && 2216 _pFieldAttr->Which() == EE_FEATURE_FIELD; 2217 //on every new field move the end position 2218 if(bIsField) 2219 nEndField = bIsField ? _pFieldAttr->GetEnd() : USHRT_MAX; 2220 2221 LanguageType eCurLanguage = GetLanguage( aCursor ); 2222 if(eCurLanguage != eStartLanguage || bIsField || bIsEndField) 2223 { 2224 eStartLanguage = eCurLanguage; 2225 //go one step back - the cursor currently selects the first character 2226 //with a different language 2227 //create a selection from start to the current Cursor 2228 EditSelection aSelection(aStart, aCursor); 2229 AddPortion(aSelection, xAlt, rToFill, bIsEndField); 2230 aStart = aCursor; 2231 } 2232 } 2233 while(aCursor.GetIndex() < aEnd.GetIndex()); 2234 EditSelection aSelection(aStart, aCursor); 2235 AddPortion(aSelection, xAlt, rToFill, bIsField); 2236 } 2237 } 2238 #endif 2239 } 2240 2241 /*-- 13.10.2003 16:43:33--------------------------------------------------- 2242 2243 -----------------------------------------------------------------------*/ 2244 void ImpEditEngine::ApplyChangedSentence(EditView& rEditView, 2245 const ::svx::SpellPortions& rNewPortions, 2246 bool bRecheck ) 2247 { 2248 #ifdef SVX_LIGHT 2249 #else 2250 // Note: rNewPortions.size() == 0 is valid and happens when the whole 2251 // sentence got removed in the dialog 2252 2253 DBG_ASSERT(pSpellInfo, "pSpellInfo not initialized"); 2254 if (pSpellInfo && 2255 pSpellInfo->aLastSpellPortions.size() > 0) // no portions -> no text to be changed 2256 { 2257 // get current paragraph length to calculate later on how the sentence length changed, 2258 // in order to place the cursor at the end of the sentence again 2259 EditSelection aOldSel( rEditView.pImpEditView->GetEditSelection() ); 2260 xub_StrLen nOldLen = aOldSel.Max().GetNode()->Len(); 2261 2262 UndoActionStart( EDITUNDO_INSERT ); 2263 if(pSpellInfo->aLastSpellPortions.size() == rNewPortions.size()) 2264 { 2265 DBG_ASSERT( rNewPortions.size() > 0, "rNewPortions should not be empty here" ); 2266 DBG_ASSERT( pSpellInfo->aLastSpellPortions.size() == pSpellInfo->aLastSpellContentSelections.size(), 2267 "aLastSpellPortions and aLastSpellContentSelections size mismatch" ); 2268 2269 //the simple case: the same number of elements on both sides 2270 //each changed element has to be applied to the corresponding source element 2271 svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.end(); 2272 svx::SpellPortions::const_iterator aCurrentOldPortion = pSpellInfo->aLastSpellPortions.end(); 2273 SpellContentSelections::const_iterator aCurrentOldPosition = pSpellInfo->aLastSpellContentSelections.end(); 2274 bool bSetToEnd = false; 2275 do 2276 { 2277 --aCurrentNewPortion; 2278 --aCurrentOldPortion; 2279 --aCurrentOldPosition; 2280 //set the cursor to the end of the sentence - necessary to 2281 //resume there at the next step 2282 if(!bSetToEnd) 2283 { 2284 bSetToEnd = true; 2285 rEditView.pImpEditView->SetEditSelection( aCurrentOldPosition->Max() ); 2286 } 2287 2288 sal_uInt16 nScriptType = GetI18NScriptTypeOfLanguage( aCurrentNewPortion->eLanguage ); 2289 // LanguageType eTextLanguage = GetLanguage( aCurrentOldPosition->Min() ); 2290 2291 sal_uInt16 nLangWhichId = EE_CHAR_LANGUAGE; 2292 switch(nScriptType) 2293 { 2294 case SCRIPTTYPE_ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break; 2295 case SCRIPTTYPE_COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break; 2296 } 2297 if(aCurrentNewPortion->sText != aCurrentOldPortion->sText) 2298 { 2299 //change text and apply language 2300 SfxItemSet aSet( aEditDoc.GetItemPool(), nLangWhichId, nLangWhichId); 2301 aSet.Put(SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId)); 2302 SetAttribs( *aCurrentOldPosition, aSet ); 2303 ImpInsertText( *aCurrentOldPosition, aCurrentNewPortion->sText ); 2304 } 2305 else if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage) 2306 { 2307 //apply language 2308 SfxItemSet aSet( aEditDoc.GetItemPool(), nLangWhichId, nLangWhichId); 2309 aSet.Put(SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId)); 2310 SetAttribs( *aCurrentOldPosition, aSet ); 2311 } 2312 if(aCurrentNewPortion == rNewPortions.begin()) 2313 break; 2314 } 2315 while(aCurrentNewPortion != rNewPortions.begin()); 2316 } 2317 else 2318 { 2319 DBG_ASSERT( pSpellInfo->aLastSpellContentSelections.size() > 0, "aLastSpellContentSelections should not be empty here" ); 2320 2321 //select the complete sentence 2322 SpellContentSelections::const_iterator aCurrentEndPosition = pSpellInfo->aLastSpellContentSelections.end(); 2323 --aCurrentEndPosition; 2324 SpellContentSelections::const_iterator aCurrentStartPosition = pSpellInfo->aLastSpellContentSelections.begin(); 2325 EditSelection aAllSentence(aCurrentStartPosition->Min(), aCurrentEndPosition->Max()); 2326 2327 //delete the sentence completely 2328 ImpDeleteSelection( aAllSentence ); 2329 svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.begin(); 2330 EditPaM aCurrentPaM = aAllSentence.Min(); 2331 while(aCurrentNewPortion != rNewPortions.end()) 2332 { 2333 //set the language attribute 2334 LanguageType eCurLanguage = GetLanguage( aCurrentPaM ); 2335 if(eCurLanguage != aCurrentNewPortion->eLanguage) 2336 { 2337 sal_uInt16 nScriptType = GetI18NScriptTypeOfLanguage( aCurrentNewPortion->eLanguage ); 2338 sal_uInt16 nLangWhichId = EE_CHAR_LANGUAGE; 2339 switch(nScriptType) 2340 { 2341 case SCRIPTTYPE_ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break; 2342 case SCRIPTTYPE_COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break; 2343 } 2344 SfxItemSet aSet( aEditDoc.GetItemPool(), nLangWhichId, nLangWhichId); 2345 aSet.Put(SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId)); 2346 SetAttribs( aCurrentPaM, aSet ); 2347 } 2348 //insert the new string and set the cursor to the end of the inserted string 2349 aCurrentPaM = ImpInsertText( aCurrentPaM , aCurrentNewPortion->sText ); 2350 ++aCurrentNewPortion; 2351 } 2352 } 2353 UndoActionEnd( EDITUNDO_INSERT ); 2354 2355 EditPaM aNext; 2356 if (bRecheck) 2357 aNext = pSpellInfo->aCurSentenceStart; 2358 else 2359 { 2360 // restore cursor position to the end of the modified sentence. 2361 // (This will define the continuation position for spell/grammar checking) 2362 // First: check if the sentence/para length changed 2363 sal_Int32 nDelta = rEditView.pImpEditView->GetEditSelection().Max().GetNode()->Len() - nOldLen; 2364 xub_StrLen nEndOfSentence = aOldSel.Max().GetIndex() + nDelta; 2365 aNext = EditPaM( aOldSel.Max().GetNode(), nEndOfSentence ); 2366 } 2367 rEditView.pImpEditView->SetEditSelection( aNext ); 2368 2369 FormatAndUpdate(); 2370 aEditDoc.SetModified(sal_True); 2371 } 2372 #endif 2373 } 2374 /*-- 08.09.2008 11:33:02--------------------------------------------------- 2375 2376 -----------------------------------------------------------------------*/ 2377 void ImpEditEngine::PutSpellingToSentenceStart( EditView& rEditView ) 2378 { 2379 #ifdef SVX_LIGHT 2380 #else 2381 if( pSpellInfo && pSpellInfo->aLastSpellContentSelections.size() ) 2382 { 2383 rEditView.pImpEditView->SetEditSelection( pSpellInfo->aLastSpellContentSelections.begin()->Min() ); 2384 } 2385 2386 #endif 2387 } 2388 2389 2390 void ImpEditEngine::DoOnlineSpelling( ContentNode* pThisNodeOnly, sal_Bool bSpellAtCursorPos, sal_Bool bInteruptable ) 2391 { 2392 #ifndef SVX_LIGHT 2393 /* 2394 Er wird ueber alle Absaetze iteriert, nur Absaetze mit invalidierter 2395 WrongList werden geprueft... 2396 2397 Es werden alle Woerter im invalidierten Bereich geprueft. 2398 Ist ein Wort falsch, aber noch nicht in der WrongList, oder umgekehrt, 2399 wird der Bereich des Wortes invalidiert 2400 ( kein Invalidate, sondern wenn nur Uebergaenge von richtig=>falsch, 2401 einfaches Paint, bei Uebergaengen von falsch=>richtig mit VDev 2402 ueberplaetten ) 2403 */ 2404 2405 if ( !xSpeller.is() ) 2406 return; 2407 2408 EditPaM aCursorPos; 2409 if( pActiveView && !bSpellAtCursorPos ) 2410 { 2411 DBG_CHKOBJ( pActiveView, EditView, 0 ); 2412 aCursorPos = pActiveView->pImpEditView->GetEditSelection().Max(); 2413 } 2414 sal_Bool bRestartTimer = sal_False; 2415 2416 ContentNode* pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count() - 1 ); 2417 sal_uInt16 nNodes = GetEditDoc().Count(); 2418 sal_uInt16 nInvalids = 0; 2419 Sequence< PropertyValue > aEmptySeq; 2420 for ( sal_uInt16 n = 0; n < nNodes; n++ ) 2421 { 2422 ContentNode* pNode = GetEditDoc().GetObject( n ); 2423 if ( pThisNodeOnly ) 2424 pNode = pThisNodeOnly; 2425 2426 if ( pNode->GetWrongList()->IsInvalid() ) 2427 { 2428 WrongList* pWrongList = pNode->GetWrongList(); 2429 sal_uInt16 nInvStart = pWrongList->GetInvalidStart(); 2430 sal_uInt16 nInvEnd = pWrongList->GetInvalidEnd(); 2431 2432 sal_uInt16 nWrongs = 0; // Auch im Absatz mal die Kontrolle abgeben... 2433 // sal_Bool bStop = sal_False; 2434 2435 sal_uInt16 nPaintFrom = 0xFFFF, nPaintTo = 0; 2436 sal_Bool bSimpleRepaint = sal_True; 2437 2438 pWrongList->SetValid(); 2439 2440 EditPaM aPaM( pNode, nInvStart ); 2441 EditSelection aSel( aPaM, aPaM ); 2442 while ( ( aSel.Max().GetNode() == pNode ) /* && !bStop */ ) 2443 { 2444 if ( ( aSel.Min().GetIndex() > nInvEnd ) 2445 || ( ( aSel.Max().GetNode() == pLastNode ) && ( aSel.Max().GetIndex() >= pLastNode->Len() ) ) ) 2446 break; // Dokument- oder Ungueltigkeitsbereich-Ende 2447 2448 aSel = SelectWord( aSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 2449 String aWord( GetSelected( aSel ) ); 2450 // Wenn Punkt dahinter, muss dieser mit uebergeben werden ! 2451 // Falls Abkuerzung... 2452 sal_Bool bDottAdded = sal_False; 2453 if ( aSel.Max().GetIndex() < aSel.Max().GetNode()->Len() ) 2454 { 2455 sal_Unicode cNext = aSel.Max().GetNode()->GetChar( aSel.Max().GetIndex() ); 2456 if ( cNext == '.' ) 2457 { 2458 aSel.Max().GetIndex()++; 2459 aWord += cNext; 2460 bDottAdded = sal_True; 2461 } 2462 } 2463 2464 2465 sal_Bool bChanged = sal_False; 2466 if ( aWord.Len() > 0 ) 2467 { 2468 sal_uInt16 nWStart = aSel.Min().GetIndex(); 2469 sal_uInt16 nWEnd= aSel.Max().GetIndex(); 2470 if ( !xSpeller->isValid( aWord, GetLanguage( EditPaM( aSel.Min().GetNode(), nWStart+1 ) ), aEmptySeq ) ) 2471 { 2472 // Pruefen, ob schon richtig markiert... 2473 nWrongs++; 2474 // Nur bei SimpleRepaint stoppen, sonst zu oft VDev 2475 // if ( ( nWrongs > 8 ) && bSimpleRepaint ) 2476 // { 2477 // bStop = sal_True; 2478 // pWrongList->MarkInvalid( aSel.Max().GetIndex(), nInvEnd ); 2479 // } 2480 sal_uInt16 nXEnd = bDottAdded ? nWEnd -1 : nWEnd; 2481 if ( !pWrongList->HasWrong( nWStart, nXEnd ) ) 2482 { 2483 // Wort als falsch markieren... 2484 // Aber nur, wenn nicht an Cursor-Position... 2485 sal_Bool bCursorPos = sal_False; 2486 if ( aCursorPos.GetNode() == pNode ) 2487 { 2488 if ( ( nWStart <= aCursorPos.GetIndex() ) && nWEnd >= aCursorPos.GetIndex() ) 2489 bCursorPos = sal_True; 2490 } 2491 if ( bCursorPos ) 2492 { 2493 // Dann weiter als ungueltig markieren... 2494 pWrongList->GetInvalidStart() = nWStart; 2495 pWrongList->GetInvalidEnd() = nWEnd; 2496 bRestartTimer = sal_True; 2497 } 2498 else 2499 { 2500 // Es kann sein, dass die Wrongs in der Liste nicht 2501 // genau ueber Woerter aufgespannt sind, weil die 2502 // WordDelimiters beim Expandieren nicht ausgewrtet werden. 2503 pWrongList->InsertWrong( nWStart, nXEnd, sal_True ); 2504 bChanged = sal_True; 2505 } 2506 } 2507 } 2508 else 2509 { 2510 // Pruefen, ob nicht als als falsch markiert.... 2511 if ( pWrongList->HasAnyWrong( nWStart, nWEnd ) ) 2512 { 2513 pWrongList->ClearWrongs( nWStart, nWEnd, pNode ); 2514 bSimpleRepaint = sal_False; 2515 bChanged = sal_True; 2516 } 2517 } 2518 if ( bChanged ) 2519 { 2520 if ( nPaintFrom == 0xFFFF ) 2521 nPaintFrom = nWStart; 2522 nPaintTo = nWEnd; 2523 } 2524 } 2525 2526 EditPaM aLastEnd( aSel.Max() ); 2527 aSel = WordRight( aSel.Max(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 2528 if ( bChanged && ( aSel.Min().GetNode() == pNode ) && 2529 ( ( aSel.Min().GetIndex()-aLastEnd.GetIndex() > 1 ) ) ) 2530 { 2531 // Wenn zwei Worte durch mehr Zeichen als ein Blank getrennt 2532 // sind, kann es passieren, dass beim Aufsplitten eines Wrongs 2533 // der Start den zweiten Wortes vor dem tatsaechlich Wort liegt 2534 pWrongList->ClearWrongs( aLastEnd.GetIndex(), aSel.Min().GetIndex(), pNode ); 2535 } 2536 } 2537 2538 // Invalidieren? 2539 if ( ( nPaintFrom != 0xFFFF ) ) 2540 { 2541 aStatus.GetStatusWord() |= EE_STAT_WRONGWORDCHANGED; 2542 CallStatusHdl(); 2543 2544 if ( aEditViews.Count() ) 2545 { 2546 // Bei SimpleRepaint wuerde ein uebermalen ohne VDev reichen, 2547 // aber dann muesste ich ueber alle Views, Intersecten, 2548 // Clippen, ... 2549 // Lohnt wahrscheinlich nicht. 2550 EditPaM aStartPaM( pNode, nPaintFrom ); 2551 EditPaM aEndPaM( pNode, nPaintTo ); 2552 Rectangle aStartCursor( PaMtoEditCursor( aStartPaM ) ); 2553 Rectangle aEndCursor( PaMtoEditCursor( aEndPaM ) ); 2554 DBG_ASSERT( aInvalidRec.IsEmpty(), "InvalidRect gesetzt!" ); 2555 aInvalidRec.Left() = 0; 2556 aInvalidRec.Right() = GetPaperSize().Width(); 2557 aInvalidRec.Top() = aStartCursor.Top(); 2558 aInvalidRec.Bottom() = aEndCursor.Bottom(); 2559 if ( pActiveView && pActiveView->HasSelection() ) 2560 { 2561 // Dann darf nicht ueber VDev ausgegeben werden 2562 UpdateViews( NULL ); 2563 } 2564 else if ( bSimpleRepaint ) 2565 { 2566 for ( sal_uInt16 nView = 0; nView < aEditViews.Count(); nView++ ) 2567 { 2568 EditView* pView = aEditViews[nView]; 2569 Rectangle aClipRec( aInvalidRec ); 2570 aClipRec.Intersection( pView->GetVisArea() ); 2571 if ( !aClipRec.IsEmpty() ) 2572 { 2573 // in Fensterkoordinaten umwandeln.... 2574 aClipRec.SetPos( pView->pImpEditView->GetWindowPos( aClipRec.TopLeft() ) ); 2575 // Wenn Selektion, dann VDev... 2576 Paint( pView->pImpEditView, aClipRec, pView->HasSelection() ); 2577 } 2578 } 2579 } 2580 else 2581 { 2582 UpdateViews( pActiveView ); 2583 } 2584 aInvalidRec = Rectangle(); 2585 } 2586 } 2587 // Nach zwei korrigierten Nodes die Kontrolle abgeben... 2588 nInvalids++; 2589 if ( bInteruptable && ( nInvalids >= 2 ) ) 2590 { 2591 bRestartTimer = sal_True; 2592 break; 2593 } 2594 } 2595 2596 if ( pThisNodeOnly ) 2597 break; 2598 } 2599 if ( bRestartTimer ) 2600 aOnlineSpellTimer.Start(); 2601 #endif // !SVX_LIGHT 2602 } 2603 2604 2605 EESpellState ImpEditEngine::HasSpellErrors() 2606 { 2607 DBG_ASSERT( xSpeller.is(), "Kein Speller gesetzt!" ); 2608 2609 #ifndef SVX_LIGHT 2610 ContentNode* pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count() - 1 ); 2611 EditSelection aCurSel( aEditDoc.GetStartPaM() ); 2612 2613 String aWord; 2614 Reference< XSpellAlternatives > xSpellAlt; 2615 Sequence< PropertyValue > aEmptySeq; 2616 while ( !xSpellAlt.is() ) 2617 { 2618 if ( ( aCurSel.Max().GetNode() == pLastNode ) && 2619 ( aCurSel.Max().GetIndex() >= pLastNode->Len() ) ) 2620 { 2621 return EE_SPELL_OK; 2622 } 2623 2624 aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 2625 aWord = GetSelected( aCurSel ); 2626 if ( aWord.Len() > 0 ) 2627 { 2628 LanguageType eLang = GetLanguage( aCurSel.Max() ); 2629 SvxSpellWrapper::CheckSpellLang( xSpeller, eLang ); 2630 xSpellAlt = xSpeller->spell( aWord, eLang, aEmptySeq ); 2631 } 2632 aCurSel = WordRight( aCurSel.Max(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 2633 } 2634 #endif 2635 2636 return EE_SPELL_ERRORFOUND; 2637 } 2638 2639 EESpellState ImpEditEngine::StartThesaurus( EditView* pEditView ) 2640 { 2641 #ifndef SVX_LIGHT 2642 EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); 2643 if ( !aCurSel.HasRange() ) 2644 aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); 2645 String aWord( GetSelected( aCurSel ) ); 2646 2647 Reference< XThesaurus > xThes( SvxGetThesaurus() ); 2648 if (!xThes.is()) 2649 return EE_SPELL_ERRORFOUND; 2650 2651 EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create(); 2652 AbstractThesaurusDialog* pDlg = pFact->CreateThesaurusDialog( pEditView->GetWindow(), xThes, aWord, GetLanguage( aCurSel.Max() ) ); 2653 if ( pDlg->Execute() == RET_OK ) 2654 { 2655 // Wort ersetzen... 2656 pEditView->pImpEditView->DrawSelection(); 2657 pEditView->pImpEditView->SetEditSelection( aCurSel ); 2658 pEditView->pImpEditView->DrawSelection(); 2659 pEditView->InsertText( pDlg->GetWord() ); 2660 pEditView->ShowCursor( sal_True, sal_False ); 2661 } 2662 2663 delete pDlg; 2664 return EE_SPELL_OK; 2665 #else 2666 return EE_SPELL_NOSPELLER; 2667 #endif 2668 } 2669 2670 sal_uInt16 ImpEditEngine::StartSearchAndReplace( EditView* pEditView, const SvxSearchItem& rSearchItem ) 2671 { 2672 sal_uInt16 nFound = 0; 2673 2674 #ifndef SVX_LIGHT 2675 EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); 2676 2677 // FIND_ALL ohne Mehrfachselektion nicht moeglich. 2678 if ( ( rSearchItem.GetCommand() == SVX_SEARCHCMD_FIND ) || 2679 ( rSearchItem.GetCommand() == SVX_SEARCHCMD_FIND_ALL ) ) 2680 { 2681 if ( Search( rSearchItem, pEditView ) ) 2682 nFound++; 2683 } 2684 else if ( rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE ) 2685 { 2686 // Das Wort ist selektiert, wenn der Anwender die Selektion 2687 // nicht zwischendurch manipuliert: 2688 if ( aCurSel.HasRange() ) 2689 { 2690 pEditView->InsertText( rSearchItem.GetReplaceString() ); 2691 nFound = 1; 2692 } 2693 else 2694 if( Search( rSearchItem, pEditView ) ) 2695 nFound = 1; 2696 } 2697 else if ( rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL ) 2698 { 2699 // Der Writer ersetzt alle, vorn Anfang bis Ende... 2700 SvxSearchItem aTmpItem( rSearchItem ); 2701 aTmpItem.SetBackward( sal_False ); 2702 2703 pEditView->pImpEditView->DrawSelection(); 2704 2705 aCurSel.Adjust( aEditDoc ); 2706 EditPaM aStartPaM = aTmpItem.GetSelection() ? aCurSel.Min() : aEditDoc.GetStartPaM(); 2707 EditSelection aFoundSel( aCurSel.Max() ); 2708 sal_Bool bFound = ImpSearch( aTmpItem, aCurSel, aStartPaM, aFoundSel ); 2709 if ( bFound ) 2710 UndoActionStart( EDITUNDO_REPLACEALL ); 2711 while ( bFound ) 2712 { 2713 nFound++; 2714 aStartPaM = ImpInsertText( aFoundSel, rSearchItem.GetReplaceString() ); 2715 bFound = ImpSearch( aTmpItem, aCurSel, aStartPaM, aFoundSel ); 2716 } 2717 if ( nFound ) 2718 { 2719 EditPaM aNewPaM( aFoundSel.Max() ); 2720 if ( aNewPaM.GetIndex() > aNewPaM.GetNode()->Len() ) 2721 aNewPaM.GetIndex() = aNewPaM.GetNode()->Len(); 2722 pEditView->pImpEditView->SetEditSelection( aNewPaM ); 2723 FormatAndUpdate( pEditView ); 2724 UndoActionEnd( EDITUNDO_REPLACEALL ); 2725 } 2726 else 2727 { 2728 pEditView->pImpEditView->DrawSelection(); 2729 pEditView->ShowCursor( sal_True, sal_False ); 2730 } 2731 } 2732 #endif // !SVX_LIGHT 2733 return nFound; 2734 } 2735 2736 sal_Bool ImpEditEngine::Search( const SvxSearchItem& rSearchItem, EditView* pEditView ) 2737 { 2738 EditSelection aSel( pEditView->pImpEditView->GetEditSelection() ); 2739 aSel.Adjust( aEditDoc ); 2740 EditPaM aStartPaM( aSel.Max() ); 2741 if ( rSearchItem.GetSelection() && !rSearchItem.GetBackward() ) 2742 aStartPaM = aSel.Min(); 2743 2744 EditSelection aFoundSel; 2745 sal_Bool bFound = ImpSearch( rSearchItem, aSel, aStartPaM, aFoundSel ); 2746 if ( bFound && ( aFoundSel == aSel ) ) // Bei Rueckwaetssuche 2747 { 2748 aStartPaM = aSel.Min(); 2749 bFound = ImpSearch( rSearchItem, aSel, aStartPaM, aFoundSel ); 2750 } 2751 2752 pEditView->pImpEditView->DrawSelection(); 2753 if ( bFound ) 2754 { 2755 // Erstmal das Min einstellen, damit das ganze Wort in den sichtbaren Bereich kommt. 2756 pEditView->pImpEditView->SetEditSelection( aFoundSel.Min() ); 2757 pEditView->ShowCursor( sal_True, sal_False ); 2758 pEditView->pImpEditView->SetEditSelection( aFoundSel ); 2759 } 2760 else 2761 pEditView->pImpEditView->SetEditSelection( aSel.Max() ); 2762 2763 pEditView->pImpEditView->DrawSelection(); 2764 pEditView->ShowCursor( sal_True, sal_False ); 2765 return bFound; 2766 } 2767 2768 sal_Bool ImpEditEngine::ImpSearch( const SvxSearchItem& rSearchItem, 2769 const EditSelection& rSearchSelection, const EditPaM& rStartPos, EditSelection& rFoundSel ) 2770 { 2771 #ifndef SVX_LIGHT 2772 util::SearchOptions aSearchOptions( rSearchItem.GetSearchOptions() ); 2773 aSearchOptions.Locale = GetLocale( rStartPos ); 2774 2775 sal_Bool bBack = rSearchItem.GetBackward(); 2776 sal_Bool bSearchInSelection = rSearchItem.GetSelection(); 2777 sal_uInt16 nStartNode = aEditDoc.GetPos( rStartPos.GetNode() ); 2778 sal_uInt16 nEndNode; 2779 if ( bSearchInSelection ) 2780 { 2781 nEndNode = aEditDoc.GetPos( bBack ? rSearchSelection.Min().GetNode() : rSearchSelection.Max().GetNode() ); 2782 } 2783 else 2784 { 2785 nEndNode = bBack ? 0 : aEditDoc.Count()-1; 2786 } 2787 2788 utl::TextSearch aSearcher( aSearchOptions ); 2789 2790 // ueber die Absaetze iterieren... 2791 for ( sal_uInt16 nNode = nStartNode; 2792 bBack ? ( nNode >= nEndNode ) : ( nNode <= nEndNode) ; 2793 bBack ? nNode-- : nNode++ ) 2794 { 2795 // Bei rueckwaertsuche, wenn nEndNode = 0: 2796 if ( nNode >= 0xFFFF ) 2797 return sal_False; 2798 2799 ContentNode* pNode = aEditDoc.GetObject( nNode ); 2800 2801 sal_uInt16 nStartPos = 0; 2802 sal_uInt16 nEndPos = pNode->Len(); 2803 if ( nNode == nStartNode ) 2804 { 2805 if ( bBack ) 2806 nEndPos = rStartPos.GetIndex(); 2807 else 2808 nStartPos = rStartPos.GetIndex(); 2809 } 2810 if ( ( nNode == nEndNode ) && bSearchInSelection ) 2811 { 2812 if ( bBack ) 2813 nStartPos = rSearchSelection.Min().GetIndex(); 2814 else 2815 nEndPos = rSearchSelection.Max().GetIndex(); 2816 } 2817 2818 // Suchen... 2819 XubString aParaStr( GetEditDoc().GetParaAsString( pNode ) ); 2820 bool bFound = false; 2821 if ( bBack ) 2822 { 2823 Swapsal_uIt16s( nStartPos, nEndPos ); 2824 bFound = aSearcher.SearchBkwrd( aParaStr, &nStartPos, &nEndPos); 2825 } 2826 else 2827 bFound = aSearcher.SearchFrwrd( aParaStr, &nStartPos, &nEndPos); 2828 2829 if ( bFound ) 2830 { 2831 rFoundSel.Min().SetNode( pNode ); 2832 rFoundSel.Min().SetIndex( nStartPos ); 2833 rFoundSel.Max().SetNode( pNode ); 2834 rFoundSel.Max().SetIndex( nEndPos ); 2835 return sal_True; 2836 } 2837 } 2838 #endif // !SVX_LIGHT 2839 return sal_False; 2840 } 2841 2842 sal_Bool ImpEditEngine::HasText( const SvxSearchItem& rSearchItem ) 2843 { 2844 #ifndef SVX_LIGHT 2845 SvxSearchItem aTmpItem( rSearchItem ); 2846 aTmpItem.SetBackward( sal_False ); 2847 aTmpItem.SetSelection( sal_False ); 2848 2849 EditPaM aStartPaM( aEditDoc.GetStartPaM() ); 2850 EditSelection aDummySel( aStartPaM ); 2851 EditSelection aFoundSel; 2852 return ImpSearch( aTmpItem, aDummySel, aStartPaM, aFoundSel ); 2853 #else 2854 return sal_False; 2855 #endif 2856 } 2857 2858 void ImpEditEngine::SetAutoCompleteText( const String& rStr, sal_Bool bClearTipWindow ) 2859 { 2860 #ifndef SVX_LIGHT 2861 aAutoCompleteText = rStr; 2862 if ( bClearTipWindow && pActiveView ) 2863 Help::ShowQuickHelp( pActiveView->GetWindow(), Rectangle(), String(), 0 ); 2864 #endif // !SVX_LIGHT 2865 } 2866 2867 2868 struct TransliterationChgData 2869 { 2870 sal_uInt16 nStart; 2871 xub_StrLen nLen; 2872 EditSelection aSelection; 2873 String aNewText; 2874 uno::Sequence< sal_Int32 > aOffsets; 2875 }; 2876 2877 2878 EditSelection ImpEditEngine::TransliterateText( const EditSelection& rSelection, sal_Int32 nTransliterationMode ) 2879 { 2880 uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); 2881 if (!_xBI.is()) 2882 return rSelection; 2883 2884 EditSelection aSel( rSelection ); 2885 aSel.Adjust( aEditDoc ); 2886 2887 if ( !aSel.HasRange() ) 2888 aSel = SelectWord( aSel ); 2889 2890 EditSelection aNewSel( aSel ); 2891 2892 const sal_uInt16 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); 2893 const sal_uInt16 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); 2894 2895 sal_Bool bChanges = sal_False; 2896 sal_Bool bLenChanged = sal_False; 2897 EditUndoTransliteration* pUndo = NULL; 2898 2899 utl::TransliterationWrapper aTranslitarationWrapper( ::comphelper::getProcessServiceFactory(), nTransliterationMode ); 2900 sal_Bool bConsiderLanguage = aTranslitarationWrapper.needLanguageForTheMode(); 2901 2902 for ( sal_uInt16 nNode = nStartNode; nNode <= nEndNode; nNode++ ) 2903 { 2904 ContentNode* pNode = aEditDoc.GetObject( nNode ); 2905 xub_StrLen nStartPos = 0; 2906 xub_StrLen nEndPos = pNode->Len(); 2907 if ( nNode == nStartNode ) 2908 nStartPos = aSel.Min().GetIndex(); 2909 if ( nNode == nEndNode ) // kann auch == nStart sein! 2910 nEndPos = aSel.Max().GetIndex(); 2911 2912 sal_uInt16 nCurrentStart = nStartPos; 2913 sal_uInt16 nCurrentEnd = nEndPos; 2914 sal_uInt16 nLanguage = LANGUAGE_SYSTEM; 2915 2916 // since we don't use Hiragana/Katakana or half-width/full-width transliterations here 2917 // it is fine to use ANYWORD_IGNOREWHITESPACES. (ANY_WORD btw is broken and will 2918 // occasionaly miss words in consecutive sentences). Also with ANYWORD_IGNOREWHITESPACES 2919 // text like 'just-in-time' will be converted to 'Just-In-Time' which seems to be the 2920 // proper thing to do. 2921 const sal_Int16 nWordType = i18n::WordType::ANYWORD_IGNOREWHITESPACES; 2922 2923 //! In order to have less trouble with changing text size, e.g. because 2924 //! of ligatures or � (German small sz) being resolved, we need to process 2925 //! the text replacements from end to start. 2926 //! This way the offsets for the yet to be changed words will be 2927 //! left unchanged by the already replaced text. 2928 //! For this we temporarily save the changes to be done in this vector 2929 std::vector< TransliterationChgData > aChanges; 2930 TransliterationChgData aChgData; 2931 2932 if (nTransliterationMode == i18n::TransliterationModulesExtra::TITLE_CASE) 2933 { 2934 // for 'capitalize every word' we need to iterate over each word 2935 2936 i18n::Boundary aSttBndry; 2937 i18n::Boundary aEndBndry; 2938 aSttBndry = _xBI->getWordBoundary( 2939 *pNode, nStartPos, 2940 SvxCreateLocale( GetLanguage( EditPaM( pNode, nStartPos + 1 ) ) ), 2941 nWordType, sal_True /*prefer forward direction*/); 2942 aEndBndry = _xBI->getWordBoundary( 2943 *pNode, nEndPos, 2944 SvxCreateLocale( GetLanguage( EditPaM( pNode, nEndPos + 1 ) ) ), 2945 nWordType, sal_False /*prefer backward direction*/); 2946 2947 // prevent backtracking to the previous word if selection is at word boundary 2948 if (aSttBndry.endPos <= nStartPos) 2949 { 2950 aSttBndry = _xBI->nextWord( 2951 *pNode, aSttBndry.endPos, 2952 SvxCreateLocale( GetLanguage( EditPaM( pNode, aSttBndry.endPos + 1 ) ) ), 2953 nWordType); 2954 } 2955 // prevent advancing to the next word if selection is at word boundary 2956 if (aEndBndry.startPos >= nEndPos) 2957 { 2958 aEndBndry = _xBI->previousWord( 2959 *pNode, aEndBndry.startPos, 2960 SvxCreateLocale( GetLanguage( EditPaM( pNode, aEndBndry.startPos + 1 ) ) ), 2961 nWordType); 2962 } 2963 2964 i18n::Boundary aCurWordBndry( aSttBndry ); 2965 while (aCurWordBndry.startPos <= aEndBndry.startPos) 2966 { 2967 nCurrentStart = (xub_StrLen)aCurWordBndry.startPos; 2968 nCurrentEnd = (xub_StrLen)aCurWordBndry.endPos; 2969 sal_Int32 nLen = nCurrentEnd - nCurrentStart; 2970 DBG_ASSERT( nLen > 0, "invalid word length of 0" ); 2971 #if OSL_DEBUG_LEVEL > 1 2972 String aText( pNode->Copy( nCurrentStart, nLen ) ); 2973 #endif 2974 2975 Sequence< sal_Int32 > aOffsets; 2976 String aNewText( aTranslitarationWrapper.transliterate( *pNode, 2977 GetLanguage( EditPaM( pNode, nCurrentStart + 1 ) ), 2978 nCurrentStart, nLen, &aOffsets )); 2979 2980 if (!pNode->Equals( aNewText, nCurrentStart, nLen )) 2981 { 2982 aChgData.nStart = nCurrentStart; 2983 aChgData.nLen = nLen; 2984 aChgData.aSelection = EditSelection( EditPaM( pNode, nCurrentStart ), EditPaM( pNode, nCurrentEnd ) ); 2985 aChgData.aNewText = aNewText; 2986 aChgData.aOffsets = aOffsets; 2987 aChanges.push_back( aChgData ); 2988 } 2989 #if OSL_DEBUG_LEVEL > 1 2990 String aSelTxt ( GetSelected( aChgData.aSelection ) ); 2991 (void) aSelTxt; 2992 #endif 2993 2994 aCurWordBndry = _xBI->nextWord( *pNode, nCurrentEnd, 2995 SvxCreateLocale( GetLanguage( EditPaM( pNode, nCurrentEnd + 1 ) ) ), 2996 nWordType); 2997 } 2998 DBG_ASSERT( nCurrentEnd >= aEndBndry.endPos, "failed to reach end of transliteration" ); 2999 } 3000 else if (nTransliterationMode == i18n::TransliterationModulesExtra::SENTENCE_CASE) 3001 { 3002 // for 'sentence case' we need to iterate sentence by sentence 3003 3004 sal_Int32 nLastStart = _xBI->beginOfSentence( 3005 *pNode, nEndPos, 3006 SvxCreateLocale( GetLanguage( EditPaM( pNode, nEndPos + 1 ) ) ) ); 3007 sal_Int32 nLastEnd = _xBI->endOfSentence( 3008 *pNode, nLastStart, 3009 SvxCreateLocale( GetLanguage( EditPaM( pNode, nLastStart + 1 ) ) ) ); 3010 3011 // extend nCurrentStart, nCurrentEnd to the current sentence boundaries 3012 nCurrentStart = _xBI->beginOfSentence( 3013 *pNode, nStartPos, 3014 SvxCreateLocale( GetLanguage( EditPaM( pNode, nStartPos + 1 ) ) ) ); 3015 nCurrentEnd = _xBI->endOfSentence( 3016 *pNode, nCurrentStart, 3017 SvxCreateLocale( GetLanguage( EditPaM( pNode, nCurrentStart + 1 ) ) ) ); 3018 3019 // prevent backtracking to the previous sentence if selection starts at end of a sentence 3020 if (nCurrentEnd <= nStartPos) 3021 { 3022 // now nCurrentStart is probably located on a non-letter word. (unless we 3023 // are in Asian text with no spaces...) 3024 // Thus to get the real sentence start we should locate the next real word, 3025 // that is one found by DICTIONARY_WORD 3026 i18n::Boundary aBndry = _xBI->nextWord( *pNode, nCurrentEnd, 3027 SvxCreateLocale( GetLanguage( EditPaM( pNode, nCurrentEnd + 1 ) ) ), 3028 i18n::WordType::DICTIONARY_WORD); 3029 3030 // now get new current sentence boundaries 3031 nCurrentStart = _xBI->beginOfSentence( 3032 *pNode, aBndry.startPos, 3033 SvxCreateLocale( GetLanguage( EditPaM( pNode, aBndry.startPos + 1 ) ) ) ); 3034 nCurrentEnd = _xBI->endOfSentence( 3035 *pNode, nCurrentStart, 3036 SvxCreateLocale( GetLanguage( EditPaM( pNode, nCurrentStart + 1 ) ) ) ); 3037 } 3038 // prevent advancing to the next sentence if selection ends at start of a sentence 3039 if (nLastStart >= nEndPos) 3040 { 3041 // now nCurrentStart is probably located on a non-letter word. (unless we 3042 // are in Asian text with no spaces...) 3043 // Thus to get the real sentence start we should locate the previous real word, 3044 // that is one found by DICTIONARY_WORD 3045 i18n::Boundary aBndry = _xBI->previousWord( *pNode, nLastStart, 3046 SvxCreateLocale( GetLanguage( EditPaM( pNode, nLastStart + 1 ) ) ), 3047 i18n::WordType::DICTIONARY_WORD); 3048 nLastEnd = _xBI->endOfSentence( 3049 *pNode, aBndry.startPos, 3050 SvxCreateLocale( GetLanguage( EditPaM( pNode, aBndry.startPos + 1 ) ) ) ); 3051 if (nCurrentEnd > nLastEnd) 3052 nCurrentEnd = nLastEnd; 3053 } 3054 3055 while (nCurrentStart < nLastEnd) 3056 { 3057 sal_Int32 nLen = nCurrentEnd - nCurrentStart; 3058 DBG_ASSERT( nLen > 0, "invalid word length of 0" ); 3059 #if OSL_DEBUG_LEVEL > 1 3060 String aText( pNode->Copy( nCurrentStart, nLen ) ); 3061 #endif 3062 3063 Sequence< sal_Int32 > aOffsets; 3064 String aNewText( aTranslitarationWrapper.transliterate( *pNode, 3065 GetLanguage( EditPaM( pNode, nCurrentStart + 1 ) ), 3066 nCurrentStart, nLen, &aOffsets )); 3067 3068 if (!pNode->Equals( aNewText, nCurrentStart, nLen )) 3069 { 3070 aChgData.nStart = nCurrentStart; 3071 aChgData.nLen = nLen; 3072 aChgData.aSelection = EditSelection( EditPaM( pNode, nCurrentStart ), EditPaM( pNode, nCurrentEnd ) ); 3073 aChgData.aNewText = aNewText; 3074 aChgData.aOffsets = aOffsets; 3075 aChanges.push_back( aChgData ); 3076 } 3077 3078 i18n::Boundary aFirstWordBndry; 3079 aFirstWordBndry = _xBI->nextWord( 3080 *pNode, nCurrentEnd, 3081 SvxCreateLocale( GetLanguage( EditPaM( pNode, nCurrentEnd + 1 ) ) ), 3082 nWordType); 3083 nCurrentStart = aFirstWordBndry.startPos; 3084 nCurrentEnd = _xBI->endOfSentence( 3085 *pNode, nCurrentStart, 3086 SvxCreateLocale( GetLanguage( EditPaM( pNode, nCurrentStart + 1 ) ) ) ); 3087 } 3088 DBG_ASSERT( nCurrentEnd >= nLastEnd, "failed to reach end of transliteration" ); 3089 } 3090 else 3091 { 3092 do 3093 { 3094 if ( bConsiderLanguage ) 3095 { 3096 nLanguage = GetLanguage( EditPaM( pNode, nCurrentStart+1 ), &nCurrentEnd ); 3097 if ( nCurrentEnd > nEndPos ) 3098 nCurrentEnd = nEndPos; 3099 } 3100 3101 xub_StrLen nLen = nCurrentEnd - nCurrentStart; 3102 3103 Sequence< sal_Int32 > aOffsets; 3104 String aNewText( aTranslitarationWrapper.transliterate( *pNode, nLanguage, nCurrentStart, nLen, &aOffsets ) ); 3105 3106 if (!pNode->Equals( aNewText, nCurrentStart, nLen )) 3107 { 3108 aChgData.nStart = nCurrentStart; 3109 aChgData.nLen = nLen; 3110 aChgData.aSelection = EditSelection( EditPaM( pNode, nCurrentStart ), EditPaM( pNode, nCurrentEnd ) ); 3111 aChgData.aNewText = aNewText; 3112 aChgData.aOffsets = aOffsets; 3113 aChanges.push_back( aChgData ); 3114 } 3115 3116 nCurrentStart = nCurrentEnd; 3117 } while( nCurrentEnd < nEndPos ); 3118 } 3119 3120 if (aChanges.size() > 0) 3121 { 3122 #ifndef SVX_LIGHT 3123 // Create a single UndoAction on Demand for all the changes ... 3124 if ( !pUndo && IsUndoEnabled() && !IsInUndo() ) 3125 { 3126 // adjust selection to include all changes 3127 for (size_t i = 0; i < aChanges.size(); ++i) 3128 { 3129 const EditSelection &rSel = aChanges[i].aSelection; 3130 if (aSel.Min().GetNode() == rSel.Min().GetNode() && 3131 aSel.Min().GetIndex() > rSel.Min().GetIndex()) 3132 aSel.Min().SetIndex( rSel.Min().GetIndex() ); 3133 if (aSel.Max().GetNode() == rSel.Max().GetNode() && 3134 aSel.Max().GetIndex() < rSel.Max().GetIndex()) 3135 aSel.Max().SetIndex( rSel.Max().GetIndex() ); 3136 } 3137 aNewSel = aSel; 3138 3139 ESelection aESel( CreateESel( aSel ) ); 3140 pUndo = new EditUndoTransliteration( this, aESel, nTransliterationMode ); 3141 3142 const bool bSingleNode = aSel.Min().GetNode()== aSel.Max().GetNode(); 3143 const bool bHasAttribs = aSel.Min().GetNode()->GetCharAttribs().HasAttrib( aSel.Min().GetIndex(), aSel.Max().GetIndex() ); 3144 if (bSingleNode && !bHasAttribs) 3145 pUndo->SetText( aSel.Min().GetNode()->Copy( aSel.Min().GetIndex(), aSel.Max().GetIndex()-aSel.Min().GetIndex() ) ); 3146 else 3147 pUndo->SetText( CreateBinTextObject( aSel, NULL ) ); 3148 } 3149 #endif 3150 3151 // now apply the changes from end to start to leave the offsets of the 3152 // yet unchanged text parts remain the same. 3153 for (size_t i = 0; i < aChanges.size(); ++i) 3154 { 3155 const TransliterationChgData &rData = aChanges[ aChanges.size() - 1 - i ]; 3156 3157 bChanges = sal_True; 3158 if (rData.nLen != rData.aNewText.Len()) 3159 bLenChanged = sal_True; 3160 3161 // Change text without loosing the attributes 3162 sal_uInt16 nDiffs = ReplaceTextOnly( rData.aSelection.Min().GetNode(), 3163 rData.nStart, rData.nLen, rData.aNewText, rData.aOffsets ); 3164 3165 // adjust selection in end node to possibly changed size 3166 if (aSel.Max().GetNode() == rData.aSelection.Max().GetNode()) 3167 aNewSel.Max().GetIndex() = aNewSel.Max().GetIndex() + nDiffs; 3168 3169 sal_uInt16 nSelNode = aEditDoc.GetPos( rData.aSelection.Min().GetNode() ); 3170 ParaPortion* pParaPortion = GetParaPortions()[nSelNode]; 3171 pParaPortion->MarkSelectionInvalid( rData.nStart, 3172 std::max< sal_uInt16 >( rData.nStart + rData.nLen, 3173 rData.nStart + rData.aNewText.Len() ) ); 3174 } 3175 } // if (aChanges.size() > 0) 3176 } 3177 3178 #ifndef SVX_LIGHT 3179 if ( pUndo ) 3180 { 3181 ESelection aESel( CreateESel( aNewSel ) ); 3182 pUndo->SetNewSelection( aESel ); 3183 InsertUndo( pUndo ); 3184 } 3185 #endif 3186 3187 if ( bChanges ) 3188 { 3189 TextModified(); 3190 SetModifyFlag( sal_True ); 3191 if ( bLenChanged ) 3192 UpdateSelections(); 3193 FormatAndUpdate(); 3194 } 3195 3196 return aNewSel; 3197 } 3198 3199 3200 short ImpEditEngine::ReplaceTextOnly( 3201 ContentNode* pNode, 3202 sal_uInt16 nCurrentStart, xub_StrLen nLen, 3203 const String& rNewText, 3204 const uno::Sequence< sal_Int32 >& rOffsets ) 3205 { 3206 (void) nLen; 3207 3208 // Change text without loosing the attributes 3209 sal_uInt16 nCharsAfterTransliteration = 3210 sal::static_int_cast< sal_uInt16 >(rOffsets.getLength()); 3211 const sal_Int32* pOffsets = rOffsets.getConstArray(); 3212 short nDiffs = 0; 3213 for ( sal_uInt16 n = 0; n < nCharsAfterTransliteration; n++ ) 3214 { 3215 sal_uInt16 nCurrentPos = nCurrentStart+n; 3216 sal_Int32 nDiff = (nCurrentPos-nDiffs) - pOffsets[n]; 3217 3218 if ( !nDiff ) 3219 { 3220 DBG_ASSERT( nCurrentPos < pNode->Len(), "TransliterateText - String smaller than expected!" ); 3221 pNode->SetChar( nCurrentPos, rNewText.GetChar(n) ); 3222 } 3223 else if ( nDiff < 0 ) 3224 { 3225 // Replace first char, delete the rest... 3226 DBG_ASSERT( nCurrentPos < pNode->Len(), "TransliterateText - String smaller than expected!" ); 3227 pNode->SetChar( nCurrentPos, rNewText.GetChar(n) ); 3228 3229 DBG_ASSERT( (nCurrentPos+1) < pNode->Len(), "TransliterateText - String smaller than expected!" ); 3230 GetEditDoc().RemoveChars( EditPaM( pNode, nCurrentPos+1 ), sal::static_int_cast< sal_uInt16 >(-nDiff) ); 3231 } 3232 else 3233 { 3234 DBG_ASSERT( nDiff == 1, "TransliterateText - Diff other than expected! But should work..." ); 3235 GetEditDoc().InsertText( EditPaM( pNode, nCurrentPos ), rNewText.GetChar(n) ); 3236 3237 } 3238 nDiffs = sal::static_int_cast< short >(nDiffs + nDiff); 3239 } 3240 3241 return nDiffs; 3242 } 3243 3244 3245 void ImpEditEngine::SetAsianCompressionMode( sal_uInt16 n ) 3246 { 3247 if ( n != nAsianCompressionMode ) 3248 { 3249 nAsianCompressionMode = n; 3250 if ( ImplHasText() ) 3251 { 3252 FormatFullDoc(); 3253 UpdateViews(); 3254 } 3255 } 3256 } 3257 3258 void ImpEditEngine::SetKernAsianPunctuation( sal_Bool b ) 3259 { 3260 if ( b != bKernAsianPunctuation ) 3261 { 3262 bKernAsianPunctuation = b; 3263 if ( ImplHasText() ) 3264 { 3265 FormatFullDoc(); 3266 UpdateViews(); 3267 } 3268 } 3269 } 3270 3271 void ImpEditEngine::SetAddExtLeading( sal_Bool bExtLeading ) 3272 { 3273 if ( IsAddExtLeading() != bExtLeading ) 3274 { 3275 bAddExtLeading = bExtLeading; 3276 if ( ImplHasText() ) 3277 { 3278 FormatFullDoc(); 3279 UpdateViews(); 3280 } 3281 } 3282 }; 3283 3284 3285 3286 sal_Bool ImpEditEngine::ImplHasText() const 3287 { 3288 return ( ( GetEditDoc().Count() > 1 ) || GetEditDoc().GetObject(0)->Len() ); 3289 } 3290 3291 long ImpEditEngine::LogicToTwips( long n ) 3292 { 3293 Size aSz( n, 0 ); 3294 MapMode aTwipsMode( MAP_TWIP ); 3295 aSz = pRefDev->LogicToLogic( aSz, NULL, &aTwipsMode ); 3296 return aSz.Width(); 3297 } 3298 3299 3300