1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <comphelper/string.hxx> 21 #include <utility> 22 23 #include "eertfpar.hxx" 24 #include "impedit.hxx" 25 #include <svl/intitem.hxx> 26 #include <editeng/escapementitem.hxx> 27 #include <editeng/fhgtitem.hxx> 28 #include <editeng/fontitem.hxx> 29 #include <editeng/flditem.hxx> 30 #include <editeng/editeng.hxx> 31 32 #include <svtools/rtftoken.h> 33 #include <svtools/htmltokn.h> 34 35 using namespace com::sun::star; 36 37 HtmlImportInfo::HtmlImportInfo( HtmlImportState eSt, SvParser<HtmlTokenId>* pPrsrs, const ESelection& rSel ) 38 : aSelection( rSel ) 39 { 40 pParser = pPrsrs; 41 eState = eSt; 42 nToken = HtmlTokenId::NONE; 43 } 44 45 HtmlImportInfo::~HtmlImportInfo() 46 { 47 } 48 49 RtfImportInfo::RtfImportInfo( RtfImportState eSt, SvParser<int>* pPrsrs, const ESelection& rSel ) 50 : aSelection( rSel ) 51 { 52 pParser = pPrsrs; 53 eState = eSt; 54 nToken = 0; 55 nTokenValue = 0; 56 } 57 58 RtfImportInfo::~RtfImportInfo() 59 { 60 } 61 62 static constexpr MapUnit gRTFMapUnit = MapUnit::MapTwip; 63 64 EditRTFParser::EditRTFParser( 65 SvStream& rIn, EditSelection aSel, SfxItemPool& rAttrPool, EditEngine* pEditEngine) : 66 SvxRTFParser(rAttrPool, rIn), 67 aCurSel(std::move(aSel)), 68 mpEditEngine(pEditEngine), 69 nDefFont(0), 70 bLastActionInsertParaBreak(false) 71 { 72 SetInsPos(EditPosition(mpEditEngine, &aCurSel)); 73 74 // Convert the twips values ... 75 SetCalcValue(true); 76 SetChkStyleAttr(mpEditEngine->IsImportRTFStyleSheetsSet()); 77 SetNewDoc(false); // So that the Pool-Defaults are not overwritten... 78 aEditMapMode = MapMode(mpEditEngine->GetRefDevice()->GetMapMode().GetMapUnit()); 79 } 80 81 EditRTFParser::~EditRTFParser() 82 { 83 } 84 85 SvParserState EditRTFParser::CallParser() 86 { 87 DBG_ASSERT( !aCurSel.HasRange(), "Selection for CallParser!" ); 88 // Separate the part that is imported from the rest. 89 // This expression should be used for all imports. 90 // aStart1PaM: Last position before the imported content 91 // aEnd1PaM: First position after the imported content 92 // aStart2PaM: First position of the imported content 93 // aEnd2PaM: Last position of the imported content 94 EditPaM aStart1PaM( aCurSel.Min().GetNode(), aCurSel.Min().GetIndex() ); 95 aCurSel = mpEditEngine->InsertParaBreak(aCurSel); 96 EditPaM aStart2PaM = aCurSel.Min(); 97 // Useful or not? 98 aStart2PaM.GetNode()->GetContentAttribs().GetItems().ClearItem(); 99 AddRTFDefaultValues( aStart2PaM, aStart2PaM ); 100 EditPaM aEnd1PaM = mpEditEngine->InsertParaBreak(aCurSel.Max()); 101 // aCurCel now points to the gap 102 103 if (mpEditEngine->IsRtfImportHandlerSet()) 104 { 105 RtfImportInfo aImportInfo(RtfImportState::Start, this, mpEditEngine->CreateESelection(aCurSel)); 106 mpEditEngine->CallRtfImportHandler(aImportInfo); 107 } 108 109 SvParserState _eState = SvxRTFParser::CallParser(); 110 111 if (mpEditEngine->IsRtfImportHandlerSet()) 112 { 113 RtfImportInfo aImportInfo(RtfImportState::End, this, mpEditEngine->CreateESelection(aCurSel)); 114 mpEditEngine->CallRtfImportHandler(aImportInfo); 115 } 116 117 if (bLastActionInsertParaBreak) 118 { 119 ContentNode* pCurNode = aCurSel.Max().GetNode(); 120 sal_Int32 nPara = mpEditEngine->GetEditDoc().GetPos(pCurNode); 121 ContentNode* pPrevNode = mpEditEngine->GetEditDoc().GetObject(nPara-1); 122 DBG_ASSERT( pPrevNode, "Invalid RTF-Document?!" ); 123 EditSelection aSel; 124 aSel.Min() = EditPaM( pPrevNode, pPrevNode->Len() ); 125 aSel.Max() = EditPaM( pCurNode, 0 ); 126 aCurSel.Max() = mpEditEngine->DeleteSelection(aSel); 127 } 128 EditPaM aEnd2PaM( aCurSel.Max() ); 129 //AddRTFDefaultValues( aStart2PaM, aEnd2PaM ); 130 bool bOnlyOnePara = ( aEnd2PaM.GetNode() == aStart2PaM.GetNode() ); 131 // Paste the chunk again ... 132 // Problem: Paragraph attributes may not possibly be taken over 133 // => Do Character attributes. 134 135 bool bSpecialBackward = aStart1PaM.GetNode()->Len() == 0; 136 if ( bOnlyOnePara || aStart1PaM.GetNode()->Len() ) 137 mpEditEngine->ParaAttribsToCharAttribs( aStart2PaM.GetNode() ); 138 aCurSel.Min() = mpEditEngine->ConnectParagraphs( 139 aStart1PaM.GetNode(), aStart2PaM.GetNode(), bSpecialBackward ); 140 bSpecialBackward = aEnd1PaM.GetNode()->Len() != 0; 141 // when bOnlyOnePara, then the node is gone on Connect. 142 if ( !bOnlyOnePara && aEnd1PaM.GetNode()->Len() ) 143 mpEditEngine->ParaAttribsToCharAttribs( aEnd2PaM.GetNode() ); 144 aCurSel.Max() = mpEditEngine->ConnectParagraphs( 145 ( bOnlyOnePara ? aStart1PaM.GetNode() : aEnd2PaM.GetNode() ), 146 aEnd1PaM.GetNode(), bSpecialBackward ); 147 148 return _eState; 149 } 150 151 void EditRTFParser::AddRTFDefaultValues( const EditPaM& rStart, const EditPaM& rEnd ) 152 { 153 // Problem: DefFont and DefFontHeight 154 Size aSz( 12, 0 ); 155 MapMode aPntMode( MapUnit::MapPoint ); 156 MapMode _aEditMapMode(mpEditEngine->GetRefDevice()->GetMapMode().GetMapUnit()); 157 aSz = mpEditEngine->GetRefDevice()->LogicToLogic(aSz, &aPntMode, &_aEditMapMode); 158 SvxFontHeightItem aFontHeightItem( aSz.Width(), 100, EE_CHAR_FONTHEIGHT ); 159 vcl::Font aDefFont( GetFont( nDefFont ) ); 160 SvxFontItem aFontItem( aDefFont.GetFamilyType(), aDefFont.GetFamilyName(), 161 aDefFont.GetStyleName(), aDefFont.GetPitch(), aDefFont.GetCharSet(), EE_CHAR_FONTINFO ); 162 163 sal_Int32 nStartPara = mpEditEngine->GetEditDoc().GetPos( rStart.GetNode() ); 164 sal_Int32 nEndPara = mpEditEngine->GetEditDoc().GetPos( rEnd.GetNode() ); 165 for ( sal_Int32 nPara = nStartPara; nPara <= nEndPara; nPara++ ) 166 { 167 ContentNode* pNode = mpEditEngine->GetEditDoc().GetObject( nPara ); 168 assert(pNode && "AddRTFDefaultValues - No paragraph?!"); 169 if ( !pNode->GetContentAttribs().HasItem( EE_CHAR_FONTINFO ) ) 170 pNode->GetContentAttribs().GetItems().Put( aFontItem ); 171 if ( !pNode->GetContentAttribs().HasItem( EE_CHAR_FONTHEIGHT ) ) 172 pNode->GetContentAttribs().GetItems().Put( aFontHeightItem ); 173 } 174 } 175 176 void EditRTFParser::NextToken( int nToken ) 177 { 178 switch( nToken ) 179 { 180 case RTF_DEFF: 181 { 182 nDefFont = sal_uInt16(nTokenValue); 183 } 184 break; 185 case RTF_DEFTAB: 186 break; 187 case RTF_CELL: 188 { 189 aCurSel = mpEditEngine->InsertParaBreak(aCurSel); 190 } 191 break; 192 case RTF_LINE: 193 { 194 aCurSel = mpEditEngine->InsertLineBreak(aCurSel); 195 } 196 break; 197 case RTF_FIELD: 198 { 199 ReadField(); 200 } 201 break; 202 case RTF_SHPINST: // fdo#76776 process contents of shpinst 203 break; 204 case RTF_SP: // fdo#76776 but skip SP groups 205 { 206 SkipGroup(); 207 } 208 break; 209 case RTF_PGDSCTBL: // #i29453# ignore \*\pgdsctbl destination 210 case RTF_LISTTEXT: 211 { 212 SkipGroup(); 213 } 214 break; 215 default: 216 { 217 SvxRTFParser::NextToken( nToken ); 218 if ( nToken == RTF_STYLESHEET ) 219 CreateStyleSheets(); 220 } 221 break; 222 } 223 if (mpEditEngine->IsRtfImportHandlerSet()) 224 { 225 RtfImportInfo aImportInfo(RtfImportState::NextToken, this, mpEditEngine->CreateESelection(aCurSel)); 226 aImportInfo.nToken = nToken; 227 aImportInfo.nTokenValue = short(nTokenValue); 228 mpEditEngine->CallRtfImportHandler(aImportInfo); 229 } 230 } 231 232 void EditRTFParser::UnknownAttrToken( int nToken, SfxItemSet* ) 233 { 234 // for Tokens which are not evaluated in ReadAttr 235 // Actually, only for Calc (RTFTokenHdl), so that RTF_INTBL 236 if (mpEditEngine->IsRtfImportHandlerSet()) 237 { 238 RtfImportInfo aImportInfo(RtfImportState::UnknownAttr, this, mpEditEngine->CreateESelection(aCurSel)); 239 aImportInfo.nToken = nToken; 240 aImportInfo.nTokenValue = short(nTokenValue); 241 mpEditEngine->CallRtfImportHandler(aImportInfo); 242 } 243 } 244 245 void EditRTFParser::InsertText() 246 { 247 OUString aText( aToken ); 248 if (mpEditEngine->IsRtfImportHandlerSet()) 249 { 250 RtfImportInfo aImportInfo(RtfImportState::InsertText, this, mpEditEngine->CreateESelection(aCurSel)); 251 mpEditEngine->CallRtfImportHandler(aImportInfo); 252 } 253 aCurSel = mpEditEngine->InsertText(aCurSel, aText); 254 bLastActionInsertParaBreak = false; 255 } 256 257 void EditRTFParser::InsertPara() 258 { 259 if (mpEditEngine->IsRtfImportHandlerSet()) 260 { 261 RtfImportInfo aImportInfo(RtfImportState::InsertPara, this, mpEditEngine->CreateESelection(aCurSel)); 262 mpEditEngine->CallRtfImportHandler(aImportInfo); 263 } 264 aCurSel = mpEditEngine->InsertParaBreak(aCurSel); 265 bLastActionInsertParaBreak = true; 266 } 267 268 void EditRTFParser::MovePos( bool const bForward ) 269 { 270 if( bForward ) 271 aCurSel = mpEditEngine->CursorRight( 272 aCurSel.Max(), i18n::CharacterIteratorMode::SKIPCHARACTER); 273 else 274 aCurSel = mpEditEngine->CursorLeft( 275 aCurSel.Max(), i18n::CharacterIteratorMode::SKIPCHARACTER); 276 } 277 278 void EditRTFParser::SetEndPrevPara( EditNodeIdx*& rpNodePos, 279 sal_Int32& rCntPos ) 280 { 281 // The Intention is to: determine the current insert position of the 282 // previous paragraph and set the end from this. 283 // This "\pard" always apply on the right paragraph. 284 285 ContentNode* pN = aCurSel.Max().GetNode(); 286 sal_Int32 nCurPara = mpEditEngine->GetEditDoc().GetPos( pN ); 287 DBG_ASSERT( nCurPara != 0, "Paragraph equal to 0: SetEnfPrevPara" ); 288 if ( nCurPara ) 289 nCurPara--; 290 ContentNode* pPrevNode = mpEditEngine->GetEditDoc().GetObject( nCurPara ); 291 assert(pPrevNode && "pPrevNode = 0!"); 292 rpNodePos = new EditNodeIdx(mpEditEngine, pPrevNode); 293 rCntPos = pPrevNode->Len(); 294 } 295 296 bool EditRTFParser::IsEndPara( EditNodeIdx* pNd, sal_Int32 nCnt ) const 297 { 298 return nCnt == pNd->GetNode()->Len(); 299 } 300 301 void EditRTFParser::SetAttrInDoc( SvxRTFItemStackType &rSet ) 302 { 303 ContentNode* pSttNode = const_cast<EditNodeIdx&>(rSet.GetSttNode()).GetNode(); 304 ContentNode* pEndNode = const_cast<EditNodeIdx&>(rSet.GetEndNode()).GetNode(); 305 306 EditPaM aStartPaM( pSttNode, rSet.GetSttCnt() ); 307 EditPaM aEndPaM( pEndNode, rSet.GetEndCnt() ); 308 309 // If possible adjust the Escapement-Item: 310 const SfxPoolItem* pItem; 311 312 // #i66167# adapt font heights to destination MapUnit if necessary 313 const MapUnit eDestUnit = mpEditEngine->GetEditDoc().GetItemPool().GetMetric(0); 314 if (eDestUnit != gRTFMapUnit) 315 { 316 sal_uInt16 const aFntHeightIems[3] = { EE_CHAR_FONTHEIGHT, EE_CHAR_FONTHEIGHT_CJK, EE_CHAR_FONTHEIGHT_CTL }; 317 for (unsigned short aFntHeightIem : aFntHeightIems) 318 { 319 if (SfxItemState::SET == rSet.GetAttrSet().GetItemState( aFntHeightIem, false, &pItem )) 320 { 321 sal_uInt32 nHeight = static_cast<const SvxFontHeightItem*>(pItem)->GetHeight(); 322 long nNewHeight; 323 nNewHeight = OutputDevice::LogicToLogic( static_cast<long>(nHeight), gRTFMapUnit, eDestUnit ); 324 325 SvxFontHeightItem aFntHeightItem( nNewHeight, 100, aFntHeightIem ); 326 aFntHeightItem.SetProp( 327 static_cast<const SvxFontHeightItem*>(pItem)->GetProp(), 328 static_cast<const SvxFontHeightItem*>(pItem)->GetPropUnit()); 329 rSet.GetAttrSet().Put( aFntHeightItem ); 330 } 331 } 332 } 333 334 if( SfxItemState::SET == rSet.GetAttrSet().GetItemState( EE_CHAR_ESCAPEMENT, false, &pItem )) 335 { 336 // the correct one 337 long nEsc = static_cast<const SvxEscapementItem*>(pItem)->GetEsc(); 338 long nEscFontHeight = 0; 339 if( ( DFLT_ESC_AUTO_SUPER != nEsc ) && ( DFLT_ESC_AUTO_SUB != nEsc ) ) 340 { 341 nEsc *= 10; //HalfPoints => Twips was embezzled in RTFITEM.CXX! 342 SvxFont aFont; 343 mpEditEngine->SeekCursor(aStartPaM.GetNode(), aStartPaM.GetIndex()+1, aFont); 344 nEscFontHeight = aFont.GetFontSize().Height(); 345 } 346 if (nEscFontHeight) 347 { 348 nEsc = nEsc * 100 / nEscFontHeight; 349 350 SvxEscapementItem aEscItem( static_cast<short>(nEsc), static_cast<const SvxEscapementItem*>(pItem)->GetProportionalHeight(), EE_CHAR_ESCAPEMENT ); 351 rSet.GetAttrSet().Put( aEscItem ); 352 } 353 } 354 355 if (mpEditEngine->IsRtfImportHandlerSet()) 356 { 357 EditSelection aSel( aStartPaM, aEndPaM ); 358 RtfImportInfo aImportInfo(RtfImportState::SetAttr, this, mpEditEngine->CreateESelection(aSel)); 359 mpEditEngine->CallRtfImportHandler(aImportInfo); 360 } 361 362 ContentNode* pSN = aStartPaM.GetNode(); 363 ContentNode* pEN = aEndPaM.GetNode(); 364 sal_Int32 nStartNode = mpEditEngine->GetEditDoc().GetPos( pSN ); 365 sal_Int32 nEndNode = mpEditEngine->GetEditDoc().GetPos( pEN ); 366 sal_Int16 nOutlLevel = 0xff; 367 368 if (rSet.StyleNo() && mpEditEngine->GetStyleSheetPool() && mpEditEngine->IsImportRTFStyleSheetsSet()) 369 { 370 SvxRTFStyleTbl::iterator it = GetStyleTbl().find( rSet.StyleNo() ); 371 DBG_ASSERT( it != GetStyleTbl().end(), "Template not defined in RTF!" ); 372 if ( it != GetStyleTbl().end() ) 373 { 374 auto const& pS = it->second; 375 mpEditEngine->SetStyleSheet( 376 EditSelection(aStartPaM, aEndPaM), 377 static_cast<SfxStyleSheet*>(mpEditEngine->GetStyleSheetPool()->Find(pS->sName, SfxStyleFamily::All))); 378 nOutlLevel = pS->nOutlineNo; 379 } 380 } 381 382 // When an Attribute goes from 0 to the current paragraph length, 383 // it should be a paragraph attribute! 384 385 // Note: Selection can reach over several paragraphs. 386 // All Complete paragraphs are paragraph attributes ... 387 for ( sal_Int32 z = nStartNode+1; z < nEndNode; z++ ) 388 { 389 DBG_ASSERT(mpEditEngine->GetEditDoc().GetObject(z), "Node does not exist yet(RTF)"); 390 mpEditEngine->SetParaAttribsOnly(z, rSet.GetAttrSet()); 391 } 392 393 if ( aStartPaM.GetNode() != aEndPaM.GetNode() ) 394 { 395 // The rest of the StartNodes... 396 if ( aStartPaM.GetIndex() == 0 ) 397 mpEditEngine->SetParaAttribsOnly(nStartNode, rSet.GetAttrSet()); 398 else 399 mpEditEngine->SetAttribs( 400 EditSelection(aStartPaM, EditPaM(aStartPaM.GetNode(), aStartPaM.GetNode()->Len())), rSet.GetAttrSet()); 401 402 // the beginning of the EndNodes.... 403 if ( aEndPaM.GetIndex() == aEndPaM.GetNode()->Len() ) 404 mpEditEngine->SetParaAttribsOnly(nEndNode, rSet.GetAttrSet()); 405 else 406 mpEditEngine->SetAttribs( 407 EditSelection(EditPaM(aEndPaM.GetNode(), 0), aEndPaM), rSet.GetAttrSet()); 408 } 409 else 410 { 411 if ( ( aStartPaM.GetIndex() == 0 ) && ( aEndPaM.GetIndex() == aEndPaM.GetNode()->Len() ) ) 412 { 413 // When settings char attribs as para attribs, we must merge with existing attribs, not overwrite the ItemSet! 414 SfxItemSet aAttrs = mpEditEngine->GetBaseParaAttribs(nStartNode); 415 aAttrs.Put( rSet.GetAttrSet() ); 416 mpEditEngine->SetParaAttribsOnly(nStartNode, aAttrs); 417 } 418 else 419 { 420 mpEditEngine->SetAttribs( 421 EditSelection(aStartPaM, aEndPaM), rSet.GetAttrSet()); 422 } 423 } 424 425 // OutlLevel... 426 if ( nOutlLevel != 0xff ) 427 { 428 for ( sal_Int32 n = nStartNode; n <= nEndNode; n++ ) 429 { 430 ContentNode* pNode = mpEditEngine->GetEditDoc().GetObject( n ); 431 pNode->GetContentAttribs().GetItems().Put( SfxInt16Item( EE_PARA_OUTLLEVEL, nOutlLevel ) ); 432 } 433 } 434 } 435 436 SvxRTFStyleType* EditRTFParser::FindStyleSheet( const OUString& rName ) 437 { 438 SvxRTFStyleTbl& rTable = GetStyleTbl(); 439 for (auto const& iter : rTable) 440 { 441 if (iter.second->sName == rName) 442 return iter.second.get(); 443 } 444 return nullptr; 445 } 446 447 SfxStyleSheet* EditRTFParser::CreateStyleSheet( SvxRTFStyleType const * pRTFStyle ) 448 { 449 // Check if a template exists, then it will not be changed! 450 SfxStyleSheet* pStyle = static_cast<SfxStyleSheet*>(mpEditEngine->GetStyleSheetPool()->Find( pRTFStyle->sName, SfxStyleFamily::All )); 451 if ( pStyle ) 452 return pStyle; 453 454 OUString aName( pRTFStyle->sName ); 455 OUString aParent; 456 if ( pRTFStyle->nBasedOn ) 457 { 458 SvxRTFStyleTbl::iterator it = GetStyleTbl().find( pRTFStyle->nBasedOn ); 459 if ( it != GetStyleTbl().end()) 460 { 461 SvxRTFStyleType *const pS = it->second.get(); 462 if ( pS && ( pS !=pRTFStyle ) ) 463 aParent = pS->sName; 464 } 465 } 466 467 pStyle = static_cast<SfxStyleSheet*>( &mpEditEngine->GetStyleSheetPool()->Make( aName, SfxStyleFamily::Para ) ); 468 469 // 1) convert and take over Items ... 470 ConvertAndPutItems( pStyle->GetItemSet(), pRTFStyle->aAttrSet ); 471 472 // 2) As long as Parent is not in the pool, also create this ... 473 if ( !aParent.isEmpty() && ( aParent != aName ) ) 474 { 475 SfxStyleSheet* pS = static_cast<SfxStyleSheet*>(mpEditEngine->GetStyleSheetPool()->Find( aParent, SfxStyleFamily::All )); 476 if ( !pS ) 477 { 478 // If not found anywhere, create from RTF ... 479 SvxRTFStyleType* _pRTFStyle = FindStyleSheet( aParent ); 480 if ( _pRTFStyle ) 481 pS = CreateStyleSheet( _pRTFStyle ); 482 } 483 // 2b) Link Itemset with Parent ... 484 if ( pS ) 485 pStyle->GetItemSet().SetParent( &pS->GetItemSet() ); 486 } 487 return pStyle; 488 } 489 490 void EditRTFParser::CreateStyleSheets() 491 { 492 // the SvxRTFParser has now created the template... 493 if (mpEditEngine->GetStyleSheetPool() && mpEditEngine->IsImportRTFStyleSheetsSet()) 494 { 495 for (auto const& elem : GetStyleTbl()) 496 { 497 SvxRTFStyleType* pRTFStyle = elem.second.get(); 498 CreateStyleSheet( pRTFStyle ); 499 } 500 } 501 } 502 503 void EditRTFParser::CalcValue() 504 { 505 const MapUnit eDestUnit = aEditMapMode.GetMapUnit(); 506 if (eDestUnit != gRTFMapUnit) 507 nTokenValue = OutputDevice::LogicToLogic( nTokenValue, gRTFMapUnit, eDestUnit ); 508 } 509 510 void EditRTFParser::ReadField() 511 { 512 // From SwRTFParser::ReadField() 513 int _nOpenBrakets = 1; // the first was already detected earlier 514 bool bFldInst = false; 515 bool bFldRslt = false; 516 OUString aFldInst; 517 OUString aFldRslt; 518 519 while( _nOpenBrakets && IsParserWorking() ) 520 { 521 switch( GetNextToken() ) 522 { 523 case '}': 524 { 525 _nOpenBrakets--; 526 if ( _nOpenBrakets == 1 ) 527 { 528 bFldInst = false; 529 bFldRslt = false; 530 } 531 } 532 break; 533 534 case '{': _nOpenBrakets++; 535 break; 536 537 case RTF_FIELD: SkipGroup(); 538 break; 539 540 case RTF_FLDINST: bFldInst = true; 541 break; 542 543 case RTF_FLDRSLT: bFldRslt = true; 544 break; 545 546 case RTF_TEXTTOKEN: 547 { 548 if ( bFldInst ) 549 aFldInst += aToken; 550 else if ( bFldRslt ) 551 aFldRslt += aToken; 552 } 553 break; 554 } 555 } 556 if ( !aFldInst.isEmpty() ) 557 { 558 OUString aHyperLinkMarker( "HYPERLINK " ); 559 if ( aFldInst.startsWithIgnoreAsciiCase( aHyperLinkMarker ) ) 560 { 561 aFldInst = aFldInst.copy( aHyperLinkMarker.getLength() ); 562 aFldInst = comphelper::string::strip(aFldInst, ' '); 563 // strip start and end quotes 564 aFldInst = aFldInst.copy( 1, aFldInst.getLength()-2 ); 565 566 if ( aFldRslt.isEmpty() ) 567 aFldRslt = aFldInst; 568 569 SvxFieldItem aField( SvxURLField( aFldInst, aFldRslt, SvxURLFormat::Repr ), EE_FEATURE_FIELD ); 570 aCurSel = mpEditEngine->InsertField(aCurSel, aField); 571 mpEditEngine->UpdateFieldsOnly(); 572 bLastActionInsertParaBreak = false; 573 } 574 } 575 576 SkipToken(); // the closing brace is evaluated "above" 577 } 578 579 void EditRTFParser::SkipGroup() 580 { 581 int _nOpenBrakets = 1; // the first was already detected earlier 582 583 while( _nOpenBrakets && IsParserWorking() ) 584 { 585 switch( GetNextToken() ) 586 { 587 case '}': 588 { 589 _nOpenBrakets--; 590 } 591 break; 592 593 case '{': 594 { 595 _nOpenBrakets++; 596 } 597 break; 598 } 599 } 600 601 SkipToken(); // the closing brace is evaluated "above" 602 } 603 604 EditNodeIdx::EditNodeIdx(EditEngine* pEE, ContentNode* pNd) : 605 mpEditEngine(pEE), mpNode(pNd) {} 606 607 sal_Int32 EditNodeIdx::GetIdx() const 608 { 609 return mpEditEngine->GetEditDoc().GetPos(mpNode); 610 } 611 612 EditPosition::EditPosition(EditEngine* pEE, EditSelection* pSel) : 613 mpEditEngine(pEE), mpCurSel(pSel) {} 614 615 std::unique_ptr<EditPosition> EditPosition::Clone() const 616 { 617 return std::unique_ptr<EditPosition>(new EditPosition(mpEditEngine, mpCurSel)); 618 } 619 620 EditNodeIdx* EditPosition::MakeNodeIdx() const 621 { 622 return new EditNodeIdx(mpEditEngine, mpCurSel->Max().GetNode()); 623 } 624 625 sal_Int32 EditPosition::GetNodeIdx() const 626 { 627 ContentNode* pN = mpCurSel->Max().GetNode(); 628 return mpEditEngine->GetEditDoc().GetPos(pN); 629 } 630 631 sal_Int32 EditPosition::GetCntIdx() const 632 { 633 return mpCurSel->Max().GetIndex(); 634 } 635 636 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 637
