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_sw.hxx" 26 27 28 #include <MarkManager.hxx> 29 #include <bookmrk.hxx> 30 #include <boost/bind.hpp> 31 #include <cntfrm.hxx> 32 #include <crossrefbookmark.hxx> 33 #include <annotationmark.hxx> 34 #include <dcontact.hxx> 35 #include <doc.hxx> 36 #include <docary.hxx> 37 #include <xmloff/odffields.hxx> 38 #include <editsh.hxx> 39 #include <errhdl.hxx> 40 #include <fmtanchr.hxx> 41 #include <frmfmt.hxx> 42 #include <functional> 43 #include <hintids.hxx> 44 #include <mvsave.hxx> 45 #include <ndtxt.hxx> 46 #include <node.hxx> 47 #include <pam.hxx> 48 #include <redline.hxx> 49 #include <rolbck.hxx> 50 #include <rtl/ustrbuf.hxx> 51 #include <rtl/ustring.hxx> 52 #include <sal/types.h> 53 #include <sortedobjs.hxx> 54 #include <sfx2/linkmgr.hxx> 55 #include <swserv.hxx> 56 #include <swundo.hxx> 57 #include <tools/pstm.hxx> 58 #include <unocrsr.hxx> 59 #include <viscrs.hxx> 60 #include <stdio.h> 61 62 63 using namespace ::sw::mark; 64 65 namespace 66 { 67 static bool lcl_GreaterThan( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx ) 68 { 69 return pIdx != NULL 70 ? ( rPos.nNode > rNdIdx 71 || ( rPos.nNode == rNdIdx 72 && rPos.nContent >= pIdx->GetIndex() ) ) 73 : rPos.nNode >= rNdIdx; 74 } 75 76 static bool lcl_Lower( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx ) 77 { 78 return rPos.nNode < rNdIdx 79 || ( pIdx != NULL 80 && rPos.nNode == rNdIdx 81 && rPos.nContent < pIdx->GetIndex() ); 82 } 83 84 static bool lcl_MarkOrderingByStart(const IDocumentMarkAccess::pMark_t& rpFirst, 85 const IDocumentMarkAccess::pMark_t& rpSecond) 86 { 87 return rpFirst->GetMarkStart() < rpSecond->GetMarkStart(); 88 } 89 90 static bool lcl_MarkOrderingByEnd(const IDocumentMarkAccess::pMark_t& rpFirst, 91 const IDocumentMarkAccess::pMark_t& rpSecond) 92 { 93 return rpFirst->GetMarkEnd() < rpSecond->GetMarkEnd(); 94 } 95 96 static void lcl_InsertMarkSorted(IDocumentMarkAccess::container_t& io_vMarks, 97 const IDocumentMarkAccess::pMark_t& pMark) 98 { 99 io_vMarks.insert( 100 lower_bound( 101 io_vMarks.begin(), 102 io_vMarks.end(), 103 pMark, 104 &lcl_MarkOrderingByStart), 105 pMark); 106 } 107 108 static inline ::std::auto_ptr<SwPosition> lcl_PositionFromCntntNode( 109 SwCntntNode * const pCntntNode, 110 const bool bAtEnd=false) 111 { 112 ::std::auto_ptr<SwPosition> pResult(new SwPosition(*pCntntNode)); 113 pResult->nContent.Assign(pCntntNode, bAtEnd ? pCntntNode->Len() : 0); 114 return pResult; 115 } 116 117 // return a position at the begin of rEnd, if it is a CntntNode 118 // else set it to the begin of the Node after rEnd, if there is one 119 // else set it to the end of the node before rStt 120 // else set it to the CntntNode of the Pos outside the Range 121 static inline ::std::auto_ptr<SwPosition> lcl_FindExpelPosition( 122 const SwNodeIndex& rStt, 123 const SwNodeIndex& rEnd, 124 const SwPosition& rOtherPosition) 125 { 126 SwCntntNode * pNode = rEnd.GetNode().GetCntntNode(); 127 bool bPosAtEndOfNode = false; 128 if ( pNode == NULL) 129 { 130 SwNodeIndex aEnd = SwNodeIndex(rEnd); 131 pNode = rEnd.GetNodes().GoNext( &aEnd ); 132 bPosAtEndOfNode = false; 133 } 134 if ( pNode == NULL ) 135 { 136 SwNodeIndex aStt = SwNodeIndex(rStt); 137 pNode = rStt.GetNodes().GoPrevious(&aStt); 138 bPosAtEndOfNode = true; 139 } 140 if ( pNode != NULL ) 141 { 142 return lcl_PositionFromCntntNode( pNode, bPosAtEndOfNode ); 143 } 144 145 return ::std::auto_ptr<SwPosition>(new SwPosition(rOtherPosition)); 146 }; 147 148 static IMark* lcl_getMarkAfter(const IDocumentMarkAccess::container_t& rMarks, const SwPosition& rPos) 149 { 150 IDocumentMarkAccess::const_iterator_t pMarkAfter = upper_bound( 151 rMarks.begin(), 152 rMarks.end(), 153 rPos, 154 bind(&IMark::StartsAfter, _2, _1)); // finds the first that is starting after 155 if(pMarkAfter == rMarks.end()) return NULL; 156 return pMarkAfter->get(); 157 }; 158 159 static IMark* lcl_getMarkBefore(const IDocumentMarkAccess::container_t& rMarks, const SwPosition& rPos) 160 { 161 // candidates from which to choose the mark before 162 IDocumentMarkAccess::container_t vCandidates; 163 // no need to consider marks starting after rPos 164 IDocumentMarkAccess::const_iterator_t pCandidatesEnd = upper_bound( 165 rMarks.begin(), 166 rMarks.end(), 167 rPos, 168 bind(&IMark::StartsAfter, _2, _1)); 169 vCandidates.reserve(pCandidatesEnd - rMarks.begin()); 170 // only marks ending before are candidates 171 remove_copy_if( 172 rMarks.begin(), 173 pCandidatesEnd, 174 back_inserter(vCandidates), 175 boost::bind( ::std::logical_not<bool>(), bind( &IMark::EndsBefore, _1, rPos ) ) ); 176 // no candidate left => we are in front of the first mark or there are none 177 if(!vCandidates.size()) return NULL; 178 // return the highest (last) candidate using mark end ordering 179 return max_element(vCandidates.begin(), vCandidates.end(), &lcl_MarkOrderingByEnd)->get(); 180 } 181 182 static bool lcl_FixCorrectedMark( 183 const bool bChangedPos, 184 const bool bChangedOPos, 185 MarkBase* io_pMark ) 186 { 187 if ( IDocumentMarkAccess::GetType(*io_pMark) == IDocumentMarkAccess::ANNOTATIONMARK ) 188 { 189 // annotation marks are allowed to span a table cell range. 190 // but trigger sorting to be save 191 return true; 192 } 193 194 if ( ( bChangedPos || bChangedOPos ) 195 && io_pMark->IsExpanded() 196 && io_pMark->GetOtherMarkPos().nNode.GetNode().FindTableBoxStartNode() != 197 io_pMark->GetMarkPos().nNode.GetNode().FindTableBoxStartNode() ) 198 { 199 if ( !bChangedOPos ) 200 { 201 io_pMark->SetMarkPos( io_pMark->GetOtherMarkPos() ); 202 } 203 io_pMark->ClearOtherMarkPos(); 204 DdeBookmark * const pDdeBkmk = dynamic_cast< DdeBookmark*>(io_pMark); 205 if ( pDdeBkmk != NULL 206 && pDdeBkmk->IsServer() ) 207 { 208 pDdeBkmk->SetRefObject(NULL); 209 } 210 return true; 211 } 212 return false; 213 } 214 215 static IDocumentMarkAccess::iterator_t lcl_FindMark( 216 IDocumentMarkAccess::container_t& rMarks, 217 const IDocumentMarkAccess::pMark_t& rpMarkToFind) 218 { 219 IDocumentMarkAccess::iterator_t ppCurrentMark = lower_bound( 220 rMarks.begin(), rMarks.end(), 221 rpMarkToFind, &lcl_MarkOrderingByStart); 222 // since there are usually not too many marks on the same start 223 // position, we are not doing a bisect search for the upper bound 224 // but instead start to iterate from pMarkLow directly 225 while(ppCurrentMark != rMarks.end() && **ppCurrentMark == *rpMarkToFind) 226 { 227 if(ppCurrentMark->get() == rpMarkToFind.get()) 228 { 229 //OSL_TRACE("found mark named '%s'", 230 // ::rtl::OUStringToOString(ppCurrentMark->get()->GetName(), RTL_TEXTENCODING_UTF8).getStr()); 231 return ppCurrentMark; 232 } 233 ++ppCurrentMark; 234 } 235 // reached a mark starting on a later start pos or the end of the 236 // vector => not found 237 return rMarks.end(); 238 }; 239 240 static IDocumentMarkAccess::iterator_t lcl_FindMarkAtPos( 241 IDocumentMarkAccess::container_t& rMarks, 242 const SwPosition& rPos, 243 const IDocumentMarkAccess::MarkType eType) 244 { 245 for(IDocumentMarkAccess::iterator_t ppCurrentMark = lower_bound( 246 rMarks.begin(), rMarks.end(), 247 rPos, 248 bind(&IMark::StartsBefore, _1, _2)); 249 ppCurrentMark != rMarks.end(); 250 ++ppCurrentMark) 251 { 252 // Once we reach a mark starting after the target pos 253 // we do not need to continue 254 if(ppCurrentMark->get()->StartsAfter(rPos)) 255 break; 256 if(IDocumentMarkAccess::GetType(**ppCurrentMark) == eType) 257 { 258 //OSL_TRACE("found mark named '%s'", 259 // ::rtl::OUStringToOString(ppCurrentMark->get()->GetName(), RTL_TEXTENCODING_UTF8).getStr()); 260 return ppCurrentMark; 261 } 262 } 263 // reached a mark starting on a later start pos or the end of the 264 // vector => not found 265 return rMarks.end(); 266 }; 267 268 static IDocumentMarkAccess::const_iterator_t lcl_FindMarkByName( 269 const ::rtl::OUString& rName, 270 IDocumentMarkAccess::const_iterator_t ppMarksBegin, 271 IDocumentMarkAccess::const_iterator_t ppMarksEnd) 272 { 273 return find_if( 274 ppMarksBegin, 275 ppMarksEnd, 276 bind(&::rtl::OUString::equals, bind(&IMark::GetName, _1), rName)); 277 } 278 279 #if 0 280 static void lcl_DebugMarks(IDocumentMarkAccess::container_t vMarks) 281 { 282 OSL_TRACE("%d Marks", vMarks.size()); 283 for(IDocumentMarkAccess::iterator_t ppMark = vMarks.begin(); 284 ppMark != vMarks.end(); 285 ppMark++) 286 { 287 IMark* pMark = ppMark->get(); 288 ::rtl::OString sName = ::rtl::OUStringToOString(pMark->GetName(), RTL_TEXTENCODING_UTF8); 289 const SwPosition* const pStPos = &pMark->GetMarkStart(); 290 const SwPosition* const pEndPos = &pMark->GetMarkEnd(); 291 OSL_TRACE("%s %s %d,%d %d,%d", 292 typeid(*pMark).name(), 293 sName.getStr(), 294 pStPos->nNode.GetIndex(), 295 pStPos->nContent.GetIndex(), 296 pEndPos->nNode.GetIndex(), 297 pEndPos->nContent.GetIndex()); 298 } 299 }; 300 #endif 301 } 302 303 IDocumentMarkAccess::MarkType IDocumentMarkAccess::GetType(const IMark& rBkmk) 304 { 305 const std::type_info* const pMarkTypeInfo = &typeid(rBkmk); 306 // not using dynamic_cast<> here for performance 307 if(*pMarkTypeInfo == typeid(UnoMark)) 308 return UNO_BOOKMARK; 309 else if(*pMarkTypeInfo == typeid(DdeBookmark)) 310 return DDE_BOOKMARK; 311 else if(*pMarkTypeInfo == typeid(Bookmark)) 312 return BOOKMARK; 313 else if(*pMarkTypeInfo == typeid(CrossRefHeadingBookmark)) 314 return CROSSREF_HEADING_BOOKMARK; 315 else if(*pMarkTypeInfo == typeid(CrossRefNumItemBookmark)) 316 return CROSSREF_NUMITEM_BOOKMARK; 317 else if(*pMarkTypeInfo == typeid(AnnotationMark)) 318 return ANNOTATIONMARK; 319 else if(*pMarkTypeInfo == typeid(TextFieldmark)) 320 return TEXT_FIELDMARK; 321 else if(*pMarkTypeInfo == typeid(CheckboxFieldmark)) 322 return CHECKBOX_FIELDMARK; 323 else if(*pMarkTypeInfo == typeid(NavigatorReminder)) 324 return NAVIGATOR_REMINDER; 325 else 326 { 327 OSL_ENSURE(false, 328 "IDocumentMarkAccess::GetType(..)" 329 " - unknown MarkType. This needs to be fixed!"); 330 return UNO_BOOKMARK; 331 } 332 } 333 334 const ::rtl::OUString& IDocumentMarkAccess::GetCrossRefHeadingBookmarkNamePrefix() 335 { 336 static const ::rtl::OUString CrossRefHeadingBookmarkNamePrefix = ::rtl::OUString::createFromAscii("__RefHeading__"); 337 338 return CrossRefHeadingBookmarkNamePrefix; 339 } 340 341 bool SAL_DLLPUBLIC_EXPORT IDocumentMarkAccess::IsLegalPaMForCrossRefHeadingBookmark( const SwPaM& rPaM ) 342 { 343 bool bRet( false ); 344 345 bRet = rPaM.Start()->nNode.GetNode().IsTxtNode() && 346 rPaM.Start()->nContent.GetIndex() == 0 && 347 ( !rPaM.HasMark() || 348 ( rPaM.GetMark()->nNode == rPaM.GetPoint()->nNode && 349 rPaM.End()->nContent.GetIndex() == rPaM.End()->nNode.GetNode().GetTxtNode()->Len() ) ); 350 351 return bRet; 352 } 353 354 namespace sw { namespace mark 355 { 356 MarkManager::MarkManager(SwDoc& rDoc) 357 : m_vAllMarks() 358 , m_vBookmarks() 359 , m_vFieldmarks() 360 , m_vAnnotationMarks() 361 , m_pDoc(&rDoc) 362 { } 363 364 365 ::sw::mark::IMark* MarkManager::makeMark(const SwPaM& rPaM, 366 const ::rtl::OUString& rName, 367 const IDocumentMarkAccess::MarkType eType) 368 { 369 #if 0 370 { 371 ::rtl::OString sName = ::rtl::OUStringToOString(rName, RTL_TEXTENCODING_UTF8); 372 const SwPosition* const pPos1 = rPaM.GetPoint(); 373 const SwPosition* pPos2 = pPos1; 374 if(rPaM.HasMark()) 375 pPos2 = rPaM.GetMark(); 376 OSL_TRACE("%s %d,%d %d,%d", 377 sName.getStr(), 378 pPos1->nNode.GetIndex(), 379 pPos1->nContent.GetIndex(), 380 pPos2->nNode.GetIndex(), 381 pPos2->nContent.GetIndex()); 382 } 383 #endif 384 // see for example _SaveCntntIdx, Shells 385 OSL_PRECOND(m_vAllMarks.size() < USHRT_MAX, 386 "MarkManager::makeMark(..)" 387 " - more than USHRT_MAX marks are not supported correctly"); 388 // There should only be one CrossRefBookmark per Textnode per Type 389 OSL_PRECOND( 390 (eType != CROSSREF_NUMITEM_BOOKMARK && eType != CROSSREF_HEADING_BOOKMARK) 391 || (lcl_FindMarkAtPos(m_vBookmarks, *rPaM.GetPoint(), eType) == m_vBookmarks.end()), 392 "MarkManager::makeMark(..)" 393 " - creating duplicate CrossRefBookmark"); 394 395 // create mark 396 MarkBase* pMarkBase = NULL; 397 switch(eType) 398 { 399 case IDocumentMarkAccess::TEXT_FIELDMARK: 400 pMarkBase = new TextFieldmark(rPaM); 401 break; 402 case IDocumentMarkAccess::CHECKBOX_FIELDMARK: 403 pMarkBase = new CheckboxFieldmark(rPaM); 404 break; 405 case IDocumentMarkAccess::NAVIGATOR_REMINDER: 406 pMarkBase = new NavigatorReminder(rPaM); 407 break; 408 case IDocumentMarkAccess::BOOKMARK: 409 pMarkBase = new Bookmark(rPaM, KeyCode(), rName, ::rtl::OUString()); 410 break; 411 case IDocumentMarkAccess::DDE_BOOKMARK: 412 pMarkBase = new DdeBookmark(rPaM); 413 break; 414 case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK: 415 pMarkBase = new CrossRefHeadingBookmark(rPaM, KeyCode(), rName, ::rtl::OUString()); 416 break; 417 case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK: 418 pMarkBase = new CrossRefNumItemBookmark(rPaM, KeyCode(), rName, ::rtl::OUString()); 419 break; 420 case IDocumentMarkAccess::UNO_BOOKMARK: 421 pMarkBase = new UnoMark(rPaM); 422 break; 423 case IDocumentMarkAccess::ANNOTATIONMARK: 424 pMarkBase = new AnnotationMark( rPaM, rName ); 425 break; 426 } 427 OSL_ENSURE( pMarkBase!=NULL, 428 "MarkManager::makeMark(..)" 429 " - Mark was not created."); 430 431 pMark_t pMark = boost::shared_ptr<IMark>( pMarkBase); 432 if(pMark->GetMarkPos() != pMark->GetMarkStart()) 433 pMarkBase->Swap(); 434 435 // for performance reasons, we trust UnoMarks to have a (generated) unique name 436 if ( eType != IDocumentMarkAccess::UNO_BOOKMARK ) 437 pMarkBase->SetName( getUniqueMarkName( pMarkBase->GetName() ) ); 438 439 // register mark 440 lcl_InsertMarkSorted( m_vAllMarks, pMark ); 441 switch(eType) 442 { 443 case IDocumentMarkAccess::BOOKMARK: 444 case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK: 445 case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK: 446 // if(dynamic_cast<IBookmark*>) 447 lcl_InsertMarkSorted(m_vBookmarks, pMark); 448 break; 449 case IDocumentMarkAccess::TEXT_FIELDMARK: 450 case IDocumentMarkAccess::CHECKBOX_FIELDMARK: 451 // if(dynamic_cast<IFieldmark*> 452 lcl_InsertMarkSorted(m_vFieldmarks, pMark); 453 break; 454 case IDocumentMarkAccess::ANNOTATIONMARK: 455 lcl_InsertMarkSorted( m_vAnnotationMarks, pMark ); 456 break; 457 case IDocumentMarkAccess::NAVIGATOR_REMINDER: 458 case IDocumentMarkAccess::DDE_BOOKMARK: 459 case IDocumentMarkAccess::UNO_BOOKMARK: 460 // no special array for these 461 break; 462 } 463 pMarkBase->InitDoc(m_pDoc); 464 #if 0 465 OSL_TRACE("--- makeType ---"); 466 OSL_TRACE("Marks"); 467 lcl_DebugMarks(m_vAllMarks); 468 OSL_TRACE("Bookmarks"); 469 lcl_DebugMarks(m_vBookmarks); 470 OSL_TRACE("Fieldmarks"); 471 lcl_DebugMarks(m_vFieldmarks); 472 #endif 473 return pMark.get(); 474 } 475 476 477 ::sw::mark::IFieldmark* MarkManager::makeFieldBookmark( 478 const SwPaM& rPaM, 479 const rtl::OUString& rName, 480 const rtl::OUString& rType ) 481 { 482 sw::mark::IMark* pMark = 483 makeMark( rPaM, rName, IDocumentMarkAccess::TEXT_FIELDMARK ); 484 sw::mark::IFieldmark* pFieldMark = dynamic_cast<sw::mark::IFieldmark*>( pMark ); 485 pFieldMark->SetFieldname( rType ); 486 487 return pFieldMark; 488 } 489 490 491 ::sw::mark::IFieldmark* MarkManager::makeNoTextFieldBookmark( 492 const SwPaM& rPaM, 493 const rtl::OUString& rName, 494 const rtl::OUString& rType) 495 { 496 sw::mark::IMark* pMark = makeMark( rPaM, rName, 497 IDocumentMarkAccess::CHECKBOX_FIELDMARK ); 498 sw::mark::IFieldmark* pFieldMark = dynamic_cast<sw::mark::IFieldmark*>( pMark ); 499 pFieldMark->SetFieldname( rType ); 500 501 return pFieldMark; 502 } 503 504 505 ::sw::mark::IMark* MarkManager::getMarkForTxtNode( 506 const SwTxtNode& rTxtNode, 507 const IDocumentMarkAccess::MarkType eType ) 508 { 509 SwPosition aPos(rTxtNode); 510 aPos.nContent.Assign(&(const_cast<SwTxtNode&>(rTxtNode)), 0); 511 const iterator_t ppExistingMark = lcl_FindMarkAtPos(m_vBookmarks, aPos, eType); 512 if(ppExistingMark != m_vBookmarks.end()) 513 return ppExistingMark->get(); 514 const SwPaM aPaM(aPos); 515 return makeMark(aPaM, ::rtl::OUString(), eType); 516 } 517 518 519 sw::mark::IMark* MarkManager::makeAnnotationMark( 520 const SwPaM& rPaM, 521 const ::rtl::OUString& rName ) 522 { 523 return makeMark( rPaM, rName, IDocumentMarkAccess::ANNOTATIONMARK ); 524 } 525 526 void MarkManager::repositionMark( 527 ::sw::mark::IMark* const io_pMark, 528 const SwPaM& rPaM) 529 { 530 OSL_PRECOND(io_pMark->GetMarkPos().GetDoc() == m_pDoc, 531 "<MarkManager::repositionMark(..)>" 532 " - Mark is not in my doc."); 533 MarkBase* const pMarkBase = dynamic_cast< MarkBase* >(io_pMark); 534 pMarkBase->SetMarkPos(*(rPaM.GetPoint())); 535 if(rPaM.HasMark()) 536 pMarkBase->SetOtherMarkPos(*(rPaM.GetMark())); 537 else 538 pMarkBase->ClearOtherMarkPos(); 539 540 if(pMarkBase->GetMarkPos() != pMarkBase->GetMarkStart()) 541 pMarkBase->Swap(); 542 543 sortMarks(); 544 } 545 546 547 bool MarkManager::renameMark( 548 ::sw::mark::IMark* io_pMark, 549 const ::rtl::OUString& rNewName ) 550 { 551 OSL_PRECOND(io_pMark->GetMarkPos().GetDoc() == m_pDoc, 552 "<MarkManager::repositionMark(..)>" 553 " - Mark is not in my doc."); 554 if ( io_pMark->GetName() == rNewName ) 555 return true; 556 if ( findMark(rNewName) != m_vAllMarks.end() ) 557 return false; 558 dynamic_cast< ::sw::mark::MarkBase* >(io_pMark)->SetName(rNewName); 559 return true; 560 } 561 562 563 void MarkManager::correctMarksAbsolute( 564 const SwNodeIndex& rOldNode, 565 const SwPosition& rNewPos, 566 const xub_StrLen nOffset) 567 { 568 const SwNode* const pOldNode = &rOldNode.GetNode(); 569 SwPosition aNewPos(rNewPos); 570 aNewPos.nContent += nOffset; 571 bool isSortingNeeded = false; 572 573 for(iterator_t ppMark = m_vAllMarks.begin(); 574 ppMark != m_vAllMarks.end(); 575 ppMark++) 576 { 577 ::sw::mark::MarkBase* pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get()); 578 // is on position ?? 579 bool bChangedPos = false; 580 if(&pMark->GetMarkPos().nNode.GetNode() == pOldNode) 581 { 582 pMark->SetMarkPos(aNewPos); 583 bChangedPos = true; 584 } 585 bool bChangedOPos = false; 586 if (pMark->IsExpanded() && 587 &pMark->GetOtherMarkPos().nNode.GetNode() == pOldNode) 588 { 589 pMark->SetMarkPos(aNewPos); 590 bChangedOPos= true; 591 } 592 // illegal selection? collapse the mark and restore sorting later 593 isSortingNeeded |= lcl_FixCorrectedMark(bChangedPos, bChangedOPos, pMark); 594 } 595 596 // restore sorting if needed 597 if(isSortingNeeded) 598 sortMarks(); 599 #if 0 600 OSL_TRACE("correctMarksAbsolute"); 601 lcl_DebugMarks(m_vAllMarks); 602 #endif 603 } 604 605 606 void MarkManager::correctMarksRelative(const SwNodeIndex& rOldNode, const SwPosition& rNewPos, const xub_StrLen nOffset) 607 { 608 const SwNode* const pOldNode = &rOldNode.GetNode(); 609 SwPosition aNewPos(rNewPos); 610 aNewPos.nContent += nOffset; 611 bool isSortingNeeded = false; 612 613 for(iterator_t ppMark = m_vAllMarks.begin(); 614 ppMark != m_vAllMarks.end(); 615 ppMark++) 616 { 617 // is on position ?? 618 bool bChangedPos = false, bChangedOPos = false; 619 ::sw::mark::MarkBase* const pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get()); 620 if(&pMark->GetMarkPos().nNode.GetNode() == pOldNode) 621 { 622 SwPosition aNewPosRel(aNewPos); 623 aNewPosRel.nContent += pMark->GetMarkPos().nContent.GetIndex(); 624 pMark->SetMarkPos(aNewPosRel); 625 bChangedPos = true; 626 } 627 if(pMark->IsExpanded() && 628 &pMark->GetOtherMarkPos().nNode.GetNode() == pOldNode) 629 { 630 SwPosition aNewPosRel(aNewPos); 631 aNewPosRel.nContent += pMark->GetOtherMarkPos().nContent.GetIndex(); 632 pMark->SetOtherMarkPos(aNewPosRel); 633 bChangedOPos = true; 634 } 635 // illegal selection? collapse the mark and restore sorting later 636 isSortingNeeded |= lcl_FixCorrectedMark(bChangedPos, bChangedOPos, pMark); 637 } 638 639 // restore sorting if needed 640 if(isSortingNeeded) 641 sortMarks(); 642 #if 0 643 OSL_TRACE("correctMarksRelative"); 644 lcl_DebugMarks(m_vAllMarks); 645 #endif 646 } 647 648 649 void MarkManager::deleteMarks( 650 const SwNodeIndex& rStt, 651 const SwNodeIndex& rEnd, 652 ::std::vector<SaveBookmark>* pSaveBkmk, 653 const SwIndex* pSttIdx, 654 const SwIndex* pEndIdx ) 655 { 656 ::std::vector<const_iterator_t> vMarksToDelete; 657 bool bIsSortingNeeded = false; 658 659 // boolean indicating, if at least one mark has been moved while colleting marks for deletion 660 bool bMarksMoved = false; 661 662 // copy all bookmarks in the move area to a vector storing all position data as offset 663 // reassignment is performed after the move 664 for(iterator_t ppMark = m_vAllMarks.begin(); 665 ppMark != m_vAllMarks.end(); 666 ppMark++) 667 { 668 // navigator marks should not be moved 669 // TODO: Check if this might make them invalid 670 if(IDocumentMarkAccess::GetType(**ppMark) == NAVIGATOR_REMINDER) 671 continue; 672 673 ::sw::mark::MarkBase* pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get()); 674 // on position ?? 675 bool bIsPosInRange = lcl_GreaterThan(pMark->GetMarkPos(), rStt, pSttIdx) 676 && lcl_Lower(pMark->GetMarkPos(), rEnd, pEndIdx); 677 bool bIsOtherPosInRange = pMark->IsExpanded() 678 && lcl_GreaterThan(pMark->GetOtherMarkPos(), rStt, pSttIdx) 679 && lcl_Lower(pMark->GetOtherMarkPos(), rEnd, pEndIdx); 680 // special case: completely in range, touching the end? 681 if ( pEndIdx != NULL 682 && ( ( bIsOtherPosInRange 683 && pMark->GetMarkPos().nNode == rEnd 684 && pMark->GetMarkPos().nContent == *pEndIdx ) 685 || ( bIsPosInRange 686 && pMark->IsExpanded() 687 && pMark->GetOtherMarkPos().nNode == rEnd 688 && pMark->GetOtherMarkPos().nContent == *pEndIdx ) ) ) 689 { 690 bIsPosInRange = true, bIsOtherPosInRange = true; 691 } 692 693 if ( bIsPosInRange 694 && ( bIsOtherPosInRange 695 || !pMark->IsExpanded() ) ) 696 { 697 // completely in range 698 699 bool bDeleteMark = true; 700 { 701 switch ( IDocumentMarkAccess::GetType( *pMark ) ) 702 { 703 case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK: 704 case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK: 705 // no delete of cross-reference bookmarks, if range is inside one paragraph 706 bDeleteMark = rStt != rEnd; 707 break; 708 case IDocumentMarkAccess::UNO_BOOKMARK: 709 // no delete of UNO mark, if it is not expanded and only touches the start of the range 710 bDeleteMark = bIsOtherPosInRange 711 || pMark->IsExpanded() 712 || pSttIdx == NULL 713 || !( pMark->GetMarkPos().nNode == rStt 714 && pMark->GetMarkPos().nContent == *pSttIdx ); 715 break; 716 default: 717 bDeleteMark = true; 718 break; 719 } 720 } 721 722 if ( bDeleteMark ) 723 { 724 if ( pSaveBkmk ) 725 { 726 pSaveBkmk->push_back( SaveBookmark( true, true, *pMark, rStt, pSttIdx ) ); 727 } 728 vMarksToDelete.push_back(ppMark); 729 } 730 } 731 else if ( bIsPosInRange ^ bIsOtherPosInRange ) 732 { 733 // the bookmark is partitially in the range 734 // move position of that is in the range out of it 735 736 ::std::auto_ptr< SwPosition > pNewPos; 737 { 738 if ( pEndIdx != NULL ) 739 { 740 pNewPos = ::std::auto_ptr< SwPosition >( new SwPosition( rEnd, *pEndIdx ) ); 741 } 742 else 743 { 744 pNewPos = 745 lcl_FindExpelPosition( rStt, rEnd, bIsPosInRange ? pMark->GetOtherMarkPos() : pMark->GetMarkPos() ); 746 } 747 } 748 749 bool bMoveMark = true; 750 { 751 switch ( IDocumentMarkAccess::GetType( *pMark ) ) 752 { 753 case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK: 754 case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK: 755 // no move of cross-reference bookmarks, if move occurs inside a certain node 756 bMoveMark = pMark->GetMarkPos().nNode != pNewPos->nNode; 757 break; 758 case IDocumentMarkAccess::ANNOTATIONMARK: 759 // no move of annotation marks, if method is called to collect deleted marks 760 bMoveMark = pSaveBkmk == NULL; 761 break; 762 default: 763 bMoveMark = true; 764 break; 765 } 766 } 767 if ( bMoveMark ) 768 { 769 if ( bIsPosInRange ) 770 pMark->SetMarkPos(*pNewPos); 771 else 772 pMark->SetOtherMarkPos(*pNewPos); 773 bMarksMoved = true; 774 775 // illegal selection? collapse the mark and restore sorting later 776 bIsSortingNeeded |= lcl_FixCorrectedMark( bIsPosInRange, bIsOtherPosInRange, pMark ); 777 } 778 } 779 } 780 781 // If needed, sort mark containers containing subsets of the marks in order to assure sorting. 782 // The sorting is critical for the deletion of a mark as it is searched in these container for deletion. 783 if ( vMarksToDelete.size() > 0 && bMarksMoved ) 784 { 785 sortSubsetMarks(); 786 } 787 // we just remembered the iterators to delete, so we do not need to search 788 // for the shared_ptr<> (the entry in m_vAllMarks) again 789 // reverse iteration, since erasing an entry invalidates iterators 790 // behind it (the iterators in vMarksToDelete are sorted) 791 for ( ::std::vector< const_iterator_t >::reverse_iterator pppMark = vMarksToDelete.rbegin(); 792 pppMark != vMarksToDelete.rend(); 793 ++pppMark ) 794 { 795 deleteMark(*pppMark); 796 } 797 798 if ( bIsSortingNeeded ) 799 { 800 sortMarks(); 801 } 802 803 #if 0 804 OSL_TRACE("deleteMarks"); 805 lcl_DebugMarks(m_vAllMarks); 806 #endif 807 } 808 809 810 void MarkManager::deleteMark(const const_iterator_t ppMark) 811 { 812 if(ppMark == m_vAllMarks.end()) return; 813 814 switch(IDocumentMarkAccess::GetType(**ppMark)) 815 { 816 case IDocumentMarkAccess::BOOKMARK: 817 case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK: 818 case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK: 819 { 820 IDocumentMarkAccess::iterator_t ppBookmark = lcl_FindMark(m_vBookmarks, *ppMark); 821 if ( ppBookmark != m_vBookmarks.end() ) 822 { 823 m_vBookmarks.erase(ppBookmark); 824 } 825 else 826 { 827 OSL_ENSURE( false, "<MarkManager::deleteMark(..)> - Bookmark not found in Bookmark container."); 828 } 829 } 830 break; 831 832 case IDocumentMarkAccess::TEXT_FIELDMARK: 833 case IDocumentMarkAccess::CHECKBOX_FIELDMARK: 834 { 835 IDocumentMarkAccess::iterator_t ppFieldmark = lcl_FindMark(m_vFieldmarks, *ppMark); 836 if ( ppFieldmark != m_vFieldmarks.end() ) 837 { 838 m_vFieldmarks.erase(ppFieldmark); 839 } 840 else 841 { 842 OSL_ENSURE( false, "<MarkManager::deleteMark(..)> - Fieldmark not found in Fieldmark container."); 843 } 844 845 sw::mark::TextFieldmark* pTextFieldmark = dynamic_cast<sw::mark::TextFieldmark*>(ppMark->get()); 846 if ( pTextFieldmark ) 847 { 848 pTextFieldmark->ReleaseDoc(m_pDoc); 849 } 850 851 } 852 break; 853 854 case IDocumentMarkAccess::ANNOTATIONMARK: 855 { 856 IDocumentMarkAccess::iterator_t ppAnnotationMark = lcl_FindMark(m_vAnnotationMarks, *ppMark); 857 if ( ppAnnotationMark != m_vAnnotationMarks.end() ) 858 { 859 m_vAnnotationMarks.erase(ppAnnotationMark); 860 } 861 else 862 { 863 OSL_ENSURE( false, "<MarkManager::deleteMark(..)> - Annotation Mark not found in Annotation Mark container."); 864 } 865 } 866 break; 867 868 case IDocumentMarkAccess::NAVIGATOR_REMINDER: 869 case IDocumentMarkAccess::DDE_BOOKMARK: 870 case IDocumentMarkAccess::UNO_BOOKMARK: 871 // no special marks container 872 break; 873 } 874 DdeBookmark* const pDdeBookmark = dynamic_cast<DdeBookmark*>(ppMark->get()); 875 if ( pDdeBookmark ) 876 { 877 pDdeBookmark->DeregisterFromDoc(m_pDoc); 878 } 879 // keep a temporary instance of the to-be-deleted mark in order to avoid 880 // recursive deletion of the mark triggered via its destructor. 881 // the temporary hold instance assures that the mark is deleted after the 882 // mark container has been updated. Thus, the mark could not be found anymore 883 // in the mark container by other calls trying to recursively delete the mark. 884 iterator_t aToBeDeletedMarkIter = m_vAllMarks.begin() + (ppMark - m_vAllMarks.begin()); 885 pMark_t pToBeDeletedMark = *aToBeDeletedMarkIter; 886 m_vAllMarks.erase( aToBeDeletedMarkIter ); 887 } 888 889 void MarkManager::deleteMark(const IMark* const pMark) 890 { 891 OSL_PRECOND(pMark->GetMarkPos().GetDoc() == m_pDoc, 892 "<MarkManager::repositionMark(..)>" 893 " - Mark is not in my doc."); 894 // finds the last Mark that is starting before pMark 895 // (pMarkLow < pMark) 896 iterator_t pMarkLow = 897 lower_bound( 898 m_vAllMarks.begin(), 899 m_vAllMarks.end(), 900 pMark->GetMarkStart(), 901 bind(&IMark::StartsBefore, _1, _2) ); 902 iterator_t pMarkHigh = m_vAllMarks.end(); 903 iterator_t pMarkFound = 904 find_if( 905 pMarkLow, 906 pMarkHigh, 907 boost::bind( ::std::equal_to<const IMark*>(), bind(&boost::shared_ptr<IMark>::get, _1), pMark ) ); 908 if(pMarkFound != pMarkHigh) 909 deleteMark(pMarkFound); 910 } 911 912 void MarkManager::clearAllMarks() 913 { 914 m_vFieldmarks.clear(); 915 m_vBookmarks.clear(); 916 917 m_vAnnotationMarks.clear(); 918 919 #ifdef DEBUG 920 for(iterator_t pBkmk = m_vAllMarks.begin(); 921 pBkmk != m_vAllMarks.end(); 922 ++pBkmk) 923 OSL_ENSURE( pBkmk->unique(), 924 "<MarkManager::clearAllMarks(..)> - a Bookmark is still in use."); 925 #endif 926 m_vAllMarks.clear(); 927 } 928 929 IDocumentMarkAccess::const_iterator_t MarkManager::findMark(const ::rtl::OUString& rName) const 930 { 931 return lcl_FindMarkByName(rName, m_vAllMarks.begin(), m_vAllMarks.end()); 932 } 933 934 IDocumentMarkAccess::const_iterator_t MarkManager::findBookmark(const ::rtl::OUString& rName) const 935 { 936 return lcl_FindMarkByName(rName, m_vBookmarks.begin(), m_vBookmarks.end()); 937 } 938 939 IDocumentMarkAccess::const_iterator_t MarkManager::getAllMarksBegin() const 940 { return m_vAllMarks.begin(); } 941 942 IDocumentMarkAccess::const_iterator_t MarkManager::getAllMarksEnd() const 943 { return m_vAllMarks.end(); } 944 945 sal_Int32 MarkManager::getAllMarksCount() const 946 { return m_vAllMarks.size(); } 947 948 IDocumentMarkAccess::const_iterator_t MarkManager::getBookmarksBegin() const 949 { return m_vBookmarks.begin(); } 950 951 IDocumentMarkAccess::const_iterator_t MarkManager::getBookmarksEnd() const 952 { return m_vBookmarks.end(); } 953 954 sal_Int32 MarkManager::getBookmarksCount() const 955 { return m_vBookmarks.size(); } 956 957 IFieldmark* MarkManager::getFieldmarkFor(const SwPosition& rPos) const 958 { 959 const_iterator_t pFieldmark = find_if( 960 m_vFieldmarks.begin(), 961 m_vFieldmarks.end( ), 962 bind(&IMark::IsCoveringPosition, _1, rPos)); 963 if(pFieldmark == m_vFieldmarks.end()) return NULL; 964 return dynamic_cast<IFieldmark*>(pFieldmark->get()); 965 } 966 967 IFieldmark* MarkManager::getFieldmarkAfter(const SwPosition& rPos) const 968 { return dynamic_cast<IFieldmark*>(lcl_getMarkAfter(m_vFieldmarks, rPos)); } 969 970 IFieldmark* MarkManager::getFieldmarkBefore(const SwPosition& rPos) const 971 { return dynamic_cast<IFieldmark*>(lcl_getMarkBefore(m_vFieldmarks, rPos)); } 972 973 974 IDocumentMarkAccess::const_iterator_t MarkManager::getAnnotationMarksBegin() const 975 { 976 return m_vAnnotationMarks.begin(); 977 } 978 979 IDocumentMarkAccess::const_iterator_t MarkManager::getAnnotationMarksEnd() const 980 { 981 return m_vAnnotationMarks.end(); 982 } 983 984 sal_Int32 MarkManager::getAnnotationMarksCount() const 985 { 986 return m_vAnnotationMarks.size(); 987 } 988 989 IDocumentMarkAccess::const_iterator_t MarkManager::findAnnotationMark( const ::rtl::OUString& rName ) const 990 { 991 return lcl_FindMarkByName( rName, m_vAnnotationMarks.begin(), m_vAnnotationMarks.end() ); 992 } 993 994 995 ::rtl::OUString MarkManager::getUniqueMarkName(const ::rtl::OUString& rName) const 996 { 997 OSL_ENSURE(rName.getLength(), 998 "<MarkManager::getUniqueMarkName(..)> - a name should be proposed"); 999 if ( findMark(rName) == getAllMarksEnd() ) 1000 { 1001 return rName; 1002 } 1003 1004 ::rtl::OUStringBuffer sBuf; 1005 ::rtl::OUString sTmp; 1006 for(sal_Int32 nCnt = 1; nCnt < SAL_MAX_INT32; nCnt++) 1007 { 1008 sTmp = sBuf.append(rName).append(nCnt).makeStringAndClear(); 1009 if ( findMark(sTmp) == getAllMarksEnd() ) 1010 { 1011 break; 1012 } 1013 } 1014 return sTmp; 1015 } 1016 1017 void MarkManager::assureSortedMarkContainers() const 1018 { 1019 const_cast< MarkManager* >(this)->sortMarks(); 1020 } 1021 1022 void MarkManager::sortSubsetMarks() 1023 { 1024 sort(m_vBookmarks.begin(), m_vBookmarks.end(), &lcl_MarkOrderingByStart); 1025 sort(m_vFieldmarks.begin(), m_vFieldmarks.end(), &lcl_MarkOrderingByStart); 1026 sort(m_vAnnotationMarks.begin(), m_vAnnotationMarks.end(), &lcl_MarkOrderingByStart); 1027 } 1028 1029 void MarkManager::sortMarks() 1030 { 1031 sort(m_vAllMarks.begin(), m_vAllMarks.end(), &lcl_MarkOrderingByStart); 1032 sortSubsetMarks(); 1033 } 1034 1035 #if OSL_DEBUG_LEVEL > 1 1036 void MarkManager::dumpFieldmarks( ) const 1037 { 1038 const_iterator_t pIt = m_vFieldmarks.begin(); 1039 for (; pIt != m_vFieldmarks.end( ); pIt++) 1040 { 1041 rtl::OUString str = (*pIt)->ToString(); 1042 OSL_TRACE("%s\n", 1043 ::rtl::OUStringToOString(str, RTL_TEXTENCODING_UTF8).getStr()); 1044 } 1045 } 1046 #endif 1047 1048 }} // namespace ::sw::mark 1049 1050 1051 // old implementation 1052 1053 //SV_IMPL_OP_PTRARR_SORT(SwBookmarks, SwBookmarkPtr) 1054 1055 #define PCURCRSR (_pCurrCrsr) 1056 #define FOREACHPAM_START(pSttCrsr) \ 1057 {\ 1058 SwPaM *_pStartCrsr = pSttCrsr, *_pCurrCrsr = pSttCrsr; \ 1059 do { 1060 1061 #define FOREACHPAM_END() \ 1062 } while( (_pCurrCrsr=(SwPaM *)_pCurrCrsr->GetNext()) != _pStartCrsr ); \ 1063 } 1064 #define PCURSH ((SwCrsrShell*)_pStartShell) 1065 #define FOREACHSHELL_START( pEShell ) \ 1066 {\ 1067 ViewShell *_pStartShell = pEShell; \ 1068 do { \ 1069 if( _pStartShell->IsA( TYPE( SwCrsrShell )) ) \ 1070 { 1071 1072 #define FOREACHSHELL_END( pEShell ) \ 1073 } \ 1074 } while((_pStartShell=(ViewShell*)_pStartShell->GetNext())!= pEShell ); \ 1075 } 1076 1077 namespace 1078 { 1079 // Aufbau vom Array: 2 longs, 1080 // 1. Long enthaelt Type und Position im DocArray, 1081 // 2. die ContentPosition 1082 // 1083 // CntntType -- 1084 // 0x8000 = Bookmark Pos1 1085 // 0x8001 = Bookmark Pos2 1086 // 0x2000 = Absatzgebundener Rahmen 1087 // 0x2001 = Auto-Absatzgebundener Rahmen, der umgehaengt werden soll 1088 // 0x1000 = Redline Mark 1089 // 0x1001 = Redline Point 1090 // 0x0800 = Crsr aus der CrsrShell Mark 1091 // 0x0801 = Crsr aus der CrsrShell Point 1092 // 0x0400 = UnoCrsr Mark 1093 // 0x0401 = UnoCrsr Point 1094 // 1095 1096 class _SwSaveTypeCountContent 1097 { 1098 union { 1099 struct { sal_uInt16 nType, nCount; } TC; 1100 sal_uLong nTypeCount; 1101 } TYPECOUNT; 1102 xub_StrLen nContent; 1103 1104 public: 1105 _SwSaveTypeCountContent() { TYPECOUNT.nTypeCount = 0; nContent = 0; } 1106 _SwSaveTypeCountContent( sal_uInt16 nType ) 1107 { 1108 SetTypeAndCount( nType, 0 ); 1109 nContent = 0; 1110 } 1111 _SwSaveTypeCountContent( const SvULongs& rArr, sal_uInt16& rPos ) 1112 { 1113 TYPECOUNT.nTypeCount = rArr[ rPos++ ]; 1114 nContent = static_cast<xub_StrLen>(rArr[ rPos++ ]); 1115 } 1116 void Add( SvULongs& rArr ) 1117 { 1118 rArr.Insert( TYPECOUNT.nTypeCount, rArr.Count() ); 1119 rArr.Insert( nContent, rArr.Count() ); 1120 } 1121 1122 void SetType( sal_uInt16 n ) { TYPECOUNT.TC.nType = n; } 1123 sal_uInt16 GetType() const { return TYPECOUNT.TC.nType; } 1124 void IncType() { ++TYPECOUNT.TC.nType; } 1125 void DecType() { --TYPECOUNT.TC.nType; } 1126 1127 void SetCount( sal_uInt16 n ) { TYPECOUNT.TC.nCount = n; } 1128 sal_uInt16 GetCount() const { return TYPECOUNT.TC.nCount; } 1129 sal_uInt16 IncCount() { return ++TYPECOUNT.TC.nCount; } 1130 sal_uInt16 DecCount() { return --TYPECOUNT.TC.nCount; } 1131 1132 void SetTypeAndCount( sal_uInt16 nT, sal_uInt16 nC ) 1133 { TYPECOUNT.TC.nCount = nC; TYPECOUNT.TC.nType = nT; } 1134 1135 void SetContent( xub_StrLen n ) { nContent = n; } 1136 xub_StrLen GetContent() const { return nContent; } 1137 }; 1138 1139 // #i59534: If a paragraph will be splitted we have to restore some redline positions 1140 // This help function checks a position compared with a node and an content index 1141 1142 static const int BEFORE_NODE = 0; // Position before the given node index 1143 static const int BEFORE_SAME_NODE = 1; // Same node index but content index before given content index 1144 static const int SAME_POSITION = 2; // Same node index and samecontent index 1145 static const int BEHIND_SAME_NODE = 3; // Same node index but content index behind given content index 1146 static const int BEHIND_NODE = 4; // Position behind the given node index 1147 1148 static int lcl_RelativePosition( const SwPosition& rPos, sal_uLong nNode, xub_StrLen nCntnt ) 1149 { 1150 sal_uLong nIndex = rPos.nNode.GetIndex(); 1151 int nReturn = BEFORE_NODE; 1152 if( nIndex == nNode ) 1153 { 1154 xub_StrLen nCntIdx = rPos.nContent.GetIndex(); 1155 if( nCntIdx < nCntnt ) 1156 nReturn = BEFORE_SAME_NODE; 1157 else if( nCntIdx == nCntnt ) 1158 nReturn = SAME_POSITION; 1159 else 1160 nReturn = BEHIND_SAME_NODE; 1161 } 1162 else if( nIndex > nNode ) 1163 nReturn = BEHIND_NODE; 1164 return nReturn; 1165 } 1166 1167 1168 static inline int lcl_Greater( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx ) 1169 { 1170 return rPos.nNode > rNdIdx || ( pIdx && rPos.nNode == rNdIdx && rPos.nContent > pIdx->GetIndex() ); 1171 } 1172 1173 static void lcl_ChkPaM( SvULongs& rSaveArr, sal_uLong nNode, xub_StrLen nCntnt, 1174 const SwPaM& rPam, _SwSaveTypeCountContent& rSave, 1175 sal_Bool bChkSelDirection ) 1176 { 1177 // SelektionsRichtung beachten 1178 bool bBound1IsStart = !bChkSelDirection ? sal_True : 1179 ( *rPam.GetPoint() < *rPam.GetMark() 1180 ? rPam.GetPoint() == &rPam.GetBound() 1181 : rPam.GetMark() == &rPam.GetBound()); 1182 1183 const SwPosition* pPos = &rPam.GetBound( sal_True ); 1184 if( pPos->nNode.GetIndex() == nNode && 1185 ( bBound1IsStart ? pPos->nContent.GetIndex() < nCntnt 1186 : pPos->nContent.GetIndex() <= nCntnt )) 1187 { 1188 rSave.SetContent( pPos->nContent.GetIndex() ); 1189 rSave.Add( rSaveArr ); 1190 } 1191 1192 pPos = &rPam.GetBound( sal_False ); 1193 if( pPos->nNode.GetIndex() == nNode && 1194 ( (bBound1IsStart && bChkSelDirection) 1195 ? pPos->nContent.GetIndex() <= nCntnt 1196 : pPos->nContent.GetIndex() < nCntnt )) 1197 { 1198 rSave.SetContent( pPos->nContent.GetIndex() ); 1199 rSave.IncType(); 1200 rSave.Add( rSaveArr ); 1201 rSave.DecType(); 1202 } 1203 } 1204 1205 } 1206 1207 1208 // IDocumentMarkAccess for SwDoc 1209 1210 IDocumentMarkAccess* SwDoc::getIDocumentMarkAccess() 1211 { return static_cast< IDocumentMarkAccess* >(pMarkManager.get()); } 1212 1213 const IDocumentMarkAccess* SwDoc::getIDocumentMarkAccess() const 1214 { return static_cast< IDocumentMarkAccess* >(pMarkManager.get()); } 1215 1216 // SaveBookmark 1217 1218 SaveBookmark::SaveBookmark( 1219 bool bSavePos, 1220 bool bSaveOtherPos, 1221 const IMark& rBkmk, 1222 const SwNodeIndex & rMvPos, 1223 const SwIndex* pIdx) 1224 : m_aName(rBkmk.GetName()) 1225 , m_aShortName() 1226 , m_aCode() 1227 , m_bSavePos(bSavePos) 1228 , m_bSaveOtherPos(bSaveOtherPos) 1229 , m_eOrigBkmType(IDocumentMarkAccess::GetType(rBkmk)) 1230 { 1231 const IBookmark* const pBookmark = dynamic_cast< const IBookmark* >(&rBkmk); 1232 if(pBookmark) 1233 { 1234 m_aShortName = pBookmark->GetShortName(); 1235 m_aCode = pBookmark->GetKeyCode(); 1236 1237 ::sfx2::Metadatable const*const pMetadatable( 1238 dynamic_cast< ::sfx2::Metadatable const* >(pBookmark)); 1239 if (pMetadatable) 1240 { 1241 m_pMetadataUndo = pMetadatable->CreateUndo(); 1242 } 1243 } 1244 m_nNode1 = rBkmk.GetMarkPos().nNode.GetIndex(); 1245 m_nCntnt1 = rBkmk.GetMarkPos().nContent.GetIndex(); 1246 1247 if(m_bSavePos) 1248 { 1249 m_nNode1 -= rMvPos.GetIndex(); 1250 if(pIdx && !m_nNode1) 1251 m_nCntnt1 -= pIdx->GetIndex(); 1252 } 1253 1254 if(rBkmk.IsExpanded()) 1255 { 1256 m_nNode2 = rBkmk.GetOtherMarkPos().nNode.GetIndex(); 1257 m_nCntnt2 = rBkmk.GetOtherMarkPos().nContent.GetIndex(); 1258 1259 if(m_bSaveOtherPos) 1260 { 1261 m_nNode2 -= rMvPos.GetIndex(); 1262 if(pIdx && !m_nNode2) 1263 m_nCntnt2 -= pIdx->GetIndex(); 1264 } 1265 } 1266 else 1267 m_nNode2 = ULONG_MAX, m_nCntnt2 = STRING_NOTFOUND; 1268 } 1269 1270 void SaveBookmark::SetInDoc( 1271 SwDoc* pDoc, 1272 const SwNodeIndex& rNewPos, 1273 const SwIndex* pIdx) 1274 { 1275 SwPaM aPam(rNewPos.GetNode()); 1276 if(pIdx) 1277 aPam.GetPoint()->nContent = *pIdx; 1278 1279 if(ULONG_MAX != m_nNode2) 1280 { 1281 aPam.SetMark(); 1282 1283 if(m_bSaveOtherPos) 1284 { 1285 aPam.GetMark()->nNode += m_nNode2; 1286 if(pIdx && !m_nNode2) 1287 aPam.GetMark()->nContent += m_nCntnt2; 1288 else 1289 aPam.GetMark()->nContent.Assign(aPam.GetCntntNode(sal_False), m_nCntnt2); 1290 } 1291 else 1292 { 1293 aPam.GetMark()->nNode = m_nNode2; 1294 aPam.GetMark()->nContent.Assign(aPam.GetCntntNode(sal_False), m_nCntnt2); 1295 } 1296 } 1297 1298 if(m_bSavePos) 1299 { 1300 aPam.GetPoint()->nNode += m_nNode1; 1301 1302 if(pIdx && !m_nNode1) 1303 aPam.GetPoint()->nContent += m_nCntnt1; 1304 else 1305 aPam.GetPoint()->nContent.Assign(aPam.GetCntntNode(), m_nCntnt1); 1306 } 1307 else 1308 { 1309 aPam.GetPoint()->nNode = m_nNode1; 1310 aPam.GetPoint()->nContent.Assign(aPam.GetCntntNode(), m_nCntnt1); 1311 } 1312 1313 if(!aPam.HasMark() 1314 || CheckNodesRange(aPam.GetPoint()->nNode, aPam.GetMark()->nNode, sal_True)) 1315 { 1316 ::sw::mark::IBookmark* const pBookmark = dynamic_cast< ::sw::mark::IBookmark* >(pDoc->getIDocumentMarkAccess()->makeMark(aPam, m_aName, m_eOrigBkmType)); 1317 if(pBookmark) 1318 { 1319 pBookmark->SetKeyCode(m_aCode); 1320 pBookmark->SetShortName(m_aShortName); 1321 if (m_pMetadataUndo) 1322 { 1323 ::sfx2::Metadatable * const pMeta( 1324 dynamic_cast< ::sfx2::Metadatable* >(pBookmark)); 1325 OSL_ENSURE(pMeta, "metadata undo, but not metadatable?"); 1326 if (pMeta) 1327 { 1328 pMeta->RestoreMetadata(m_pMetadataUndo); 1329 } 1330 } 1331 } 1332 } 1333 } 1334 1335 1336 // _DelBookmarks, _{Save,Restore}CntntIdx 1337 1338 void _DelBookmarks( 1339 const SwNodeIndex& rStt, 1340 const SwNodeIndex& rEnd, 1341 ::std::vector<SaveBookmark> * pSaveBkmk, 1342 const SwIndex* pSttIdx, 1343 const SwIndex* pEndIdx) 1344 { 1345 // illegal range ?? 1346 if(rStt.GetIndex() > rEnd.GetIndex() 1347 || (rStt == rEnd && (!pSttIdx || pSttIdx->GetIndex() >= pEndIdx->GetIndex()))) 1348 return; 1349 SwDoc* const pDoc = rStt.GetNode().GetDoc(); 1350 1351 pDoc->getIDocumentMarkAccess()->deleteMarks(rStt, rEnd, pSaveBkmk, pSttIdx, pEndIdx); 1352 1353 // kopiere alle Redlines, die im Move Bereich stehen in ein 1354 // Array, das alle Angaben auf die Position als Offset speichert. 1355 // Die neue Zuordung erfolgt nach dem Moven. 1356 SwRedlineTbl& rTbl = (SwRedlineTbl&)pDoc->GetRedlineTbl(); 1357 for(sal_uInt16 nCnt = 0; nCnt < rTbl.Count(); ++nCnt ) 1358 { 1359 // liegt auf der Position ?? 1360 SwRedline* pRedl = rTbl[ nCnt ]; 1361 1362 SwPosition *pRStt = &pRedl->GetBound(sal_True), 1363 *pREnd = &pRedl->GetBound(sal_False); 1364 if( *pRStt > *pREnd ) 1365 { 1366 SwPosition *pTmp = pRStt; pRStt = pREnd, pREnd = pTmp; 1367 } 1368 1369 if( lcl_Greater( *pRStt, rStt, pSttIdx ) && lcl_Lower( *pRStt, rEnd, pEndIdx )) 1370 { 1371 pRStt->nNode = rEnd; 1372 if( pEndIdx ) 1373 pRStt->nContent = *pEndIdx; 1374 else 1375 { 1376 sal_Bool bStt = sal_True; 1377 SwCntntNode* pCNd = pRStt->nNode.GetNode().GetCntntNode(); 1378 if( !pCNd && 0 == ( pCNd = pDoc->GetNodes().GoNext( &pRStt->nNode )) ) 1379 { 1380 bStt = sal_False; 1381 pRStt->nNode = rStt; 1382 if( 0 == ( pCNd = pDoc->GetNodes().GoPrevious( &pRStt->nNode )) ) 1383 { 1384 pRStt->nNode = pREnd->nNode; 1385 pCNd = pRStt->nNode.GetNode().GetCntntNode(); 1386 } 1387 } 1388 xub_StrLen nTmp = bStt ? 0 : pCNd->Len(); 1389 pRStt->nContent.Assign( pCNd, nTmp ); 1390 } 1391 } 1392 if( lcl_Greater( *pREnd, rStt, pSttIdx ) && lcl_Lower( *pREnd, rEnd, pEndIdx )) 1393 { 1394 pREnd->nNode = rStt; 1395 if( pSttIdx ) 1396 pREnd->nContent = *pSttIdx; 1397 else 1398 { 1399 sal_Bool bStt = sal_False; 1400 SwCntntNode* pCNd = pREnd->nNode.GetNode().GetCntntNode(); 1401 if( !pCNd && 0 == ( pCNd = pDoc->GetNodes().GoPrevious( &pREnd->nNode )) ) 1402 { 1403 bStt = sal_True; 1404 pREnd->nNode = rEnd; 1405 if( 0 == ( pCNd = pDoc->GetNodes().GoNext( &pREnd->nNode )) ) 1406 { 1407 pREnd->nNode = pRStt->nNode; 1408 pCNd = pREnd->nNode.GetNode().GetCntntNode(); 1409 } 1410 } 1411 xub_StrLen nTmp = bStt ? 0 : pCNd->Len(); 1412 pREnd->nContent.Assign( pCNd, nTmp ); 1413 } 1414 } 1415 } 1416 } 1417 1418 void _SaveCntntIdx(SwDoc* pDoc, 1419 sal_uLong nNode, 1420 xub_StrLen nCntnt, 1421 SvULongs& rSaveArr, 1422 sal_uInt8 nSaveFly) 1423 { 1424 // 1. Bookmarks 1425 _SwSaveTypeCountContent aSave; 1426 aSave.SetTypeAndCount( 0x8000, 0 ); 1427 1428 IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); 1429 const sal_Int32 nMarksCount = pMarkAccess->getAllMarksCount(); 1430 for ( ; aSave.GetCount() < nMarksCount; aSave.IncCount() ) 1431 { 1432 bool bMarkPosEqual = false; 1433 const ::sw::mark::IMark* pBkmk = (pMarkAccess->getAllMarksBegin() + aSave.GetCount())->get(); 1434 if(pBkmk->GetMarkPos().nNode.GetIndex() == nNode 1435 && pBkmk->GetMarkPos().nContent.GetIndex() <= nCntnt) 1436 { 1437 if(pBkmk->GetMarkPos().nContent.GetIndex() < nCntnt) 1438 { 1439 aSave.SetContent(pBkmk->GetMarkPos().nContent.GetIndex()); 1440 aSave.Add(rSaveArr); 1441 } 1442 else // if a bookmark position is equal nCntnt, the other position 1443 bMarkPosEqual = true; // has to decide if it is added to the array 1444 } 1445 1446 if(pBkmk->IsExpanded() 1447 && pBkmk->GetOtherMarkPos().nNode.GetIndex() == nNode 1448 && pBkmk->GetOtherMarkPos().nContent.GetIndex() <= nCntnt) 1449 { 1450 if(bMarkPosEqual) 1451 { // the other position is before, the (main) position is equal 1452 aSave.SetContent(pBkmk->GetMarkPos().nContent.GetIndex()); 1453 aSave.Add(rSaveArr); 1454 } 1455 aSave.SetContent(pBkmk->GetOtherMarkPos().nContent.GetIndex()); 1456 aSave.IncType(); 1457 aSave.Add(rSaveArr); 1458 aSave.DecType(); 1459 } 1460 } 1461 1462 // 2. Redlines 1463 aSave.SetTypeAndCount( 0x1000, 0 ); 1464 const SwRedlineTbl& rRedlTbl = pDoc->GetRedlineTbl(); 1465 for( ; aSave.GetCount() < rRedlTbl.Count(); aSave.IncCount() ) 1466 { 1467 const SwRedline* pRdl = rRedlTbl[ aSave.GetCount() ]; 1468 int nPointPos = lcl_RelativePosition( *pRdl->GetPoint(), nNode, nCntnt ); 1469 int nMarkPos = pRdl->HasMark() ? lcl_RelativePosition( *pRdl->GetMark(), nNode, nCntnt ) : 1470 nPointPos; 1471 // #i59534: We have to store the positions inside the same node before the insert position 1472 // and the one at the insert position if the corresponding Point/Mark position is before 1473 // the insert position. 1474 if( nPointPos == BEFORE_SAME_NODE || 1475 ( nPointPos == SAME_POSITION && nMarkPos < SAME_POSITION ) ) 1476 { 1477 aSave.SetContent( pRdl->GetPoint()->nContent.GetIndex() ); 1478 aSave.IncType(); 1479 aSave.Add( rSaveArr ); 1480 aSave.DecType(); 1481 } 1482 if( pRdl->HasMark() && ( nMarkPos == BEFORE_SAME_NODE || 1483 ( nMarkPos == SAME_POSITION && nPointPos < SAME_POSITION ) ) ) 1484 { 1485 aSave.SetContent( pRdl->GetMark()->nContent.GetIndex() ); 1486 aSave.Add( rSaveArr ); 1487 } 1488 } 1489 1490 // 4. Absatzgebundene Objekte 1491 { 1492 SwCntntNode *pNode = pDoc->GetNodes()[nNode]->GetCntntNode(); 1493 if( pNode ) 1494 { 1495 1496 SwFrm* pFrm = pNode->getLayoutFrm( pDoc->GetCurrentLayout() ); 1497 #if OSL_DEBUG_LEVEL > 1 1498 static sal_Bool bViaDoc = sal_False; 1499 if( bViaDoc ) 1500 pFrm = NULL; 1501 #endif 1502 if( pFrm ) // gibt es ein Layout? Dann ist etwas billiger... 1503 { 1504 if( pFrm->GetDrawObjs() ) 1505 { 1506 const SwSortedObjs& rDObj = *pFrm->GetDrawObjs(); 1507 for( sal_uInt32 n = rDObj.Count(); n; ) 1508 { 1509 SwAnchoredObject* pObj = rDObj[ --n ]; 1510 const SwFrmFmt& rFmt = pObj->GetFrmFmt(); 1511 const SwFmtAnchor& rAnchor = rFmt.GetAnchor(); 1512 SwPosition const*const pAPos = rAnchor.GetCntntAnchor(); 1513 if ( pAPos && 1514 ( ( nSaveFly && 1515 FLY_AT_PARA == rAnchor.GetAnchorId() ) || 1516 ( FLY_AT_CHAR == rAnchor.GetAnchorId() ) ) ) 1517 { 1518 aSave.SetType( 0x2000 ); 1519 aSave.SetContent( pAPos->nContent.GetIndex() ); 1520 1521 OSL_ENSURE( nNode == pAPos->nNode.GetIndex(), 1522 "_SaveCntntIdx: Wrong Node-Index" ); 1523 if ( FLY_AT_CHAR == rAnchor.GetAnchorId() ) 1524 { 1525 if( nCntnt <= aSave.GetContent() ) 1526 { 1527 if( SAVEFLY_SPLIT == nSaveFly ) 1528 aSave.IncType(); // = 0x2001; 1529 else 1530 continue; 1531 } 1532 } 1533 aSave.SetCount( pDoc->GetSpzFrmFmts()->Count() ); 1534 while( aSave.GetCount() && 1535 &rFmt != (*pDoc->GetSpzFrmFmts())[ 1536 aSave.DecCount() ] ) 1537 ; // nothing 1538 OSL_ENSURE( &rFmt == (*pDoc->GetSpzFrmFmts())[ 1539 aSave.GetCount() ], 1540 "_SaveCntntIdx: Lost FrameFormat" ); 1541 aSave.Add( rSaveArr ); 1542 } 1543 } 1544 } 1545 } 1546 else // Schade, kein Layout, dann ist es eben etwas teurer... 1547 { 1548 for( aSave.SetCount( pDoc->GetSpzFrmFmts()->Count() ); 1549 aSave.GetCount() ; ) 1550 { 1551 SwFrmFmt* pFrmFmt = (*pDoc->GetSpzFrmFmts())[ 1552 aSave.DecCount() ]; 1553 if ( RES_FLYFRMFMT != pFrmFmt->Which() && 1554 RES_DRAWFRMFMT != pFrmFmt->Which() ) 1555 continue; 1556 1557 const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor(); 1558 SwPosition const*const pAPos = rAnchor.GetCntntAnchor(); 1559 if ( pAPos && ( nNode == pAPos->nNode.GetIndex() ) && 1560 ( FLY_AT_PARA == rAnchor.GetAnchorId() || 1561 FLY_AT_CHAR == rAnchor.GetAnchorId() ) ) 1562 { 1563 aSave.SetType( 0x2000 ); 1564 aSave.SetContent( pAPos->nContent.GetIndex() ); 1565 if ( FLY_AT_CHAR == rAnchor.GetAnchorId() ) 1566 { 1567 if( nCntnt <= aSave.GetContent() ) 1568 { 1569 if( SAVEFLY_SPLIT == nSaveFly ) 1570 aSave.IncType(); // = 0x2001; 1571 else 1572 continue; 1573 } 1574 } 1575 aSave.Add( rSaveArr ); 1576 } 1577 } 1578 } 1579 } 1580 } 1581 // 5. CrsrShell 1582 { 1583 SwCrsrShell* pShell = pDoc->GetEditShell(); 1584 if( pShell ) 1585 { 1586 aSave.SetTypeAndCount( 0x800, 0 ); 1587 FOREACHSHELL_START( pShell ) 1588 SwPaM *_pStkCrsr = PCURSH->GetStkCrsr(); 1589 if( _pStkCrsr ) 1590 do { 1591 lcl_ChkPaM( rSaveArr, nNode, nCntnt, *_pStkCrsr, 1592 aSave, sal_False ); 1593 aSave.IncCount(); 1594 } while ( (_pStkCrsr != 0 ) && 1595 ((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) ); 1596 1597 FOREACHPAM_START( PCURSH->_GetCrsr() ) 1598 lcl_ChkPaM( rSaveArr, nNode, nCntnt, *PCURCRSR, 1599 aSave, sal_False ); 1600 aSave.IncCount(); 1601 FOREACHPAM_END() 1602 1603 FOREACHSHELL_END( pShell ) 1604 } 1605 } 1606 // 6. UnoCrsr 1607 { 1608 aSave.SetTypeAndCount( 0x400, 0 ); 1609 const SwUnoCrsrTbl& rTbl = pDoc->GetUnoCrsrTbl(); 1610 for( sal_uInt16 n = 0; n < rTbl.Count(); ++n ) 1611 { 1612 FOREACHPAM_START( rTbl[ n ] ) 1613 lcl_ChkPaM( rSaveArr, nNode, nCntnt, *PCURCRSR, aSave, sal_False ); 1614 aSave.IncCount(); 1615 FOREACHPAM_END() 1616 1617 SwUnoTableCrsr* pUnoTblCrsr = 1618 dynamic_cast<SwUnoTableCrsr*>(rTbl[ n ]); 1619 if( pUnoTblCrsr ) 1620 { 1621 FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() ) 1622 lcl_ChkPaM( rSaveArr, nNode, nCntnt, *PCURCRSR, aSave, sal_False ); 1623 aSave.IncCount(); 1624 FOREACHPAM_END() 1625 } 1626 } 1627 } 1628 } 1629 1630 1631 void _RestoreCntntIdx(SwDoc* pDoc, 1632 SvULongs& rSaveArr, 1633 sal_uLong nNode, 1634 xub_StrLen nOffset, 1635 sal_Bool bAuto) 1636 { 1637 SwCntntNode* pCNd = pDoc->GetNodes()[ nNode ]->GetCntntNode(); 1638 const SwRedlineTbl& rRedlTbl = pDoc->GetRedlineTbl(); 1639 SwSpzFrmFmts* pSpz = pDoc->GetSpzFrmFmts(); 1640 IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); 1641 sal_uInt16 n = 0; 1642 while( n < rSaveArr.Count() ) 1643 { 1644 _SwSaveTypeCountContent aSave( rSaveArr, n ); 1645 SwPosition* pPos = 0; 1646 switch( aSave.GetType() ) 1647 { 1648 case 0x8000: 1649 { 1650 MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getAllMarksBegin()[aSave.GetCount()].get()); 1651 SwPosition aNewPos(pMark->GetMarkPos()); 1652 aNewPos.nNode = *pCNd; 1653 aNewPos.nContent.Assign(pCNd, aSave.GetContent() + nOffset); 1654 pMark->SetMarkPos(aNewPos); 1655 } 1656 break; 1657 case 0x8001: 1658 { 1659 MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getAllMarksBegin()[aSave.GetCount()].get()); 1660 SwPosition aNewPos(pMark->GetOtherMarkPos()); 1661 aNewPos.nNode = *pCNd; 1662 aNewPos.nContent.Assign(pCNd, aSave.GetContent() + nOffset); 1663 pMark->SetOtherMarkPos(aNewPos); 1664 } 1665 break; 1666 case 0x1001: 1667 pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetPoint(); 1668 break; 1669 case 0x1000: 1670 pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetMark(); 1671 break; 1672 case 0x2000: 1673 { 1674 SwFrmFmt *pFrmFmt = (*pSpz)[ aSave.GetCount() ]; 1675 const SwFmtAnchor& rFlyAnchor = pFrmFmt->GetAnchor(); 1676 if( rFlyAnchor.GetCntntAnchor() ) 1677 { 1678 SwFmtAnchor aNew( rFlyAnchor ); 1679 SwPosition aNewPos( *rFlyAnchor.GetCntntAnchor() ); 1680 aNewPos.nNode = *pCNd; 1681 if ( FLY_AT_CHAR == rFlyAnchor.GetAnchorId() ) 1682 { 1683 aNewPos.nContent.Assign( pCNd, 1684 aSave.GetContent() + nOffset ); 1685 } 1686 else 1687 { 1688 aNewPos.nContent.Assign( 0, 0 ); 1689 } 1690 aNew.SetAnchor( &aNewPos ); 1691 pFrmFmt->SetFmtAttr( aNew ); 1692 } 1693 } 1694 break; 1695 case 0x2001: 1696 if( bAuto ) 1697 { 1698 SwFrmFmt *pFrmFmt = (*pSpz)[ aSave.GetCount() ]; 1699 SfxPoolItem *pAnchor = (SfxPoolItem*)&pFrmFmt->GetAnchor(); 1700 pFrmFmt->NotifyClients( pAnchor, pAnchor ); 1701 } 1702 break; 1703 1704 case 0x0800: 1705 case 0x0801: 1706 { 1707 sal_uInt16 nCnt = 0; 1708 SwCrsrShell* pShell = pDoc->GetEditShell(); 1709 if( pShell ) 1710 { 1711 FOREACHSHELL_START( pShell ) 1712 SwPaM *_pStkCrsr = PCURSH->GetStkCrsr(); 1713 if( _pStkCrsr ) 1714 do { 1715 if( aSave.GetCount() == nCnt ) 1716 { 1717 pPos = &_pStkCrsr->GetBound( 0x0800 == 1718 aSave.GetType() ); 1719 break; 1720 } 1721 ++nCnt; 1722 } while ( (_pStkCrsr != 0 ) && 1723 ((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) ); 1724 1725 if( pPos ) 1726 break; 1727 1728 FOREACHPAM_START( PCURSH->_GetCrsr() ) 1729 if( aSave.GetCount() == nCnt ) 1730 { 1731 pPos = &PCURCRSR->GetBound( 0x0800 == 1732 aSave.GetType() ); 1733 break; 1734 } 1735 ++nCnt; 1736 FOREACHPAM_END() 1737 if( pPos ) 1738 break; 1739 1740 FOREACHSHELL_END( pShell ) 1741 } 1742 } 1743 break; 1744 1745 case 0x0400: 1746 case 0x0401: 1747 { 1748 sal_uInt16 nCnt = 0; 1749 const SwUnoCrsrTbl& rTbl = pDoc->GetUnoCrsrTbl(); 1750 for( sal_uInt16 i = 0; i < rTbl.Count(); ++i ) 1751 { 1752 FOREACHPAM_START( rTbl[ i ] ) 1753 if( aSave.GetCount() == nCnt ) 1754 { 1755 pPos = &PCURCRSR->GetBound( 0x0400 == 1756 aSave.GetType() ); 1757 break; 1758 } 1759 ++nCnt; 1760 FOREACHPAM_END() 1761 if( pPos ) 1762 break; 1763 1764 SwUnoTableCrsr* pUnoTblCrsr = 1765 dynamic_cast<SwUnoTableCrsr*>(rTbl[ i ]); 1766 if ( pUnoTblCrsr ) 1767 { 1768 FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() ) 1769 if( aSave.GetCount() == nCnt ) 1770 { 1771 pPos = &PCURCRSR->GetBound( 0x0400 == 1772 aSave.GetType() ); 1773 break; 1774 } 1775 ++nCnt; 1776 FOREACHPAM_END() 1777 } 1778 if ( pPos ) 1779 break; 1780 } 1781 } 1782 break; 1783 } 1784 1785 if( pPos ) 1786 { 1787 pPos->nNode = *pCNd; 1788 pPos->nContent.Assign( pCNd, aSave.GetContent() + nOffset ); 1789 } 1790 } 1791 } 1792 1793 void _RestoreCntntIdx(SvULongs& rSaveArr, 1794 const SwNode& rNd, 1795 xub_StrLen nLen, 1796 xub_StrLen nChkLen) 1797 { 1798 const SwDoc* pDoc = rNd.GetDoc(); 1799 const SwRedlineTbl& rRedlTbl = pDoc->GetRedlineTbl(); 1800 const SwSpzFrmFmts* pSpz = pDoc->GetSpzFrmFmts(); 1801 const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); 1802 SwCntntNode* pCNd = (SwCntntNode*)rNd.GetCntntNode(); 1803 1804 sal_uInt16 n = 0; 1805 while( n < rSaveArr.Count() ) 1806 { 1807 _SwSaveTypeCountContent aSave( rSaveArr, n ); 1808 if( aSave.GetContent() >= nChkLen ) 1809 rSaveArr[ n-1 ] -= nChkLen; 1810 else 1811 { 1812 SwPosition* pPos = 0; 1813 switch( aSave.GetType() ) 1814 { 1815 case 0x8000: 1816 { 1817 MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getAllMarksBegin()[aSave.GetCount()].get()); 1818 SwPosition aNewPos(pMark->GetMarkPos()); 1819 aNewPos.nNode = rNd; 1820 aNewPos.nContent.Assign(pCNd, Min(aSave.GetContent(), nLen)); 1821 pMark->SetMarkPos(aNewPos); 1822 } 1823 break; 1824 case 0x8001: 1825 { 1826 MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getAllMarksBegin()[aSave.GetCount()].get()); 1827 SwPosition aNewPos(pMark->GetOtherMarkPos()); 1828 aNewPos.nNode = rNd; 1829 aNewPos.nContent.Assign(pCNd, Min(aSave.GetContent(), nLen)); 1830 pMark->SetOtherMarkPos(aNewPos); 1831 } 1832 break; 1833 case 0x1001: 1834 pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetPoint(); 1835 break; 1836 case 0x1000: 1837 pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetMark(); 1838 break; 1839 case 0x2000: 1840 case 0x2001: 1841 { 1842 SwFrmFmt *pFrmFmt = (*pSpz)[ aSave.GetCount() ]; 1843 const SwFmtAnchor& rFlyAnchor = pFrmFmt->GetAnchor(); 1844 if( rFlyAnchor.GetCntntAnchor() ) 1845 { 1846 SwFmtAnchor aNew( rFlyAnchor ); 1847 SwPosition aNewPos( *rFlyAnchor.GetCntntAnchor() ); 1848 aNewPos.nNode = rNd; 1849 if ( FLY_AT_CHAR == rFlyAnchor.GetAnchorId() ) 1850 { 1851 aNewPos.nContent.Assign( pCNd, Min( 1852 aSave.GetContent(), nLen ) ); 1853 } 1854 else 1855 { 1856 aNewPos.nContent.Assign( 0, 0 ); 1857 } 1858 aNew.SetAnchor( &aNewPos ); 1859 pFrmFmt->SetFmtAttr( aNew ); 1860 } 1861 } 1862 break; 1863 1864 case 0x0800: 1865 case 0x0801: 1866 { 1867 sal_uInt16 nCnt = 0; 1868 SwCrsrShell* pShell = pDoc->GetEditShell(); 1869 if( pShell ) 1870 { 1871 FOREACHSHELL_START( pShell ) 1872 SwPaM *_pStkCrsr = PCURSH->GetStkCrsr(); 1873 if( _pStkCrsr ) 1874 do { 1875 if( aSave.GetCount() == nCnt ) 1876 { 1877 pPos = &_pStkCrsr->GetBound( 0x0800 == 1878 aSave.GetType() ); 1879 break; 1880 } 1881 ++nCnt; 1882 } while ( (_pStkCrsr != 0 ) && 1883 ((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) ); 1884 1885 if( pPos ) 1886 break; 1887 1888 FOREACHPAM_START( PCURSH->_GetCrsr() ) 1889 if( aSave.GetCount() == nCnt ) 1890 { 1891 pPos = &PCURCRSR->GetBound( 0x0800 == 1892 aSave.GetType() ); 1893 break; 1894 } 1895 ++nCnt; 1896 FOREACHPAM_END() 1897 if( pPos ) 1898 break; 1899 1900 FOREACHSHELL_END( pShell ) 1901 } 1902 } 1903 break; 1904 1905 case 0x0400: 1906 case 0x0401: 1907 { 1908 sal_uInt16 nCnt = 0; 1909 const SwUnoCrsrTbl& rTbl = pDoc->GetUnoCrsrTbl(); 1910 for( sal_uInt16 i = 0; i < rTbl.Count(); ++i ) 1911 { 1912 FOREACHPAM_START( rTbl[ i ] ) 1913 if( aSave.GetCount() == nCnt ) 1914 { 1915 pPos = &PCURCRSR->GetBound( 0x0400 == 1916 aSave.GetType() ); 1917 break; 1918 } 1919 ++nCnt; 1920 FOREACHPAM_END() 1921 if( pPos ) 1922 break; 1923 1924 SwUnoTableCrsr* pUnoTblCrsr = 1925 dynamic_cast<SwUnoTableCrsr*>(rTbl[ i ]); 1926 if ( pUnoTblCrsr ) 1927 { 1928 FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() ) 1929 if( aSave.GetCount() == nCnt ) 1930 { 1931 pPos = &PCURCRSR->GetBound( 0x0400 == 1932 aSave.GetType() ); 1933 break; 1934 } 1935 ++nCnt; 1936 FOREACHPAM_END() 1937 } 1938 if ( pPos ) 1939 break; 1940 } 1941 } 1942 break; 1943 } 1944 1945 if( pPos ) 1946 { 1947 pPos->nNode = rNd; 1948 pPos->nContent.Assign( pCNd, Min( aSave.GetContent(), nLen ) ); 1949 } 1950 n -= 2; 1951 rSaveArr.Remove( n, 2 ); 1952 } 1953 } 1954 } 1955