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