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 <hintids.hxx> 29 #include <tools/list.hxx> 30 #include <vcl/vclenum.hxx> 31 #include <editeng/crsditem.hxx> 32 #include <editeng/colritem.hxx> 33 #include <editeng/boxitem.hxx> 34 #include <editeng/udlnitem.hxx> 35 #include <doc.hxx> 36 #include <IDocumentUndoRedo.hxx> 37 #include <docary.hxx> 38 #include <pam.hxx> 39 #include <ndtxt.hxx> 40 #include <redline.hxx> 41 #include <UndoRedline.hxx> 42 #include <section.hxx> 43 #include <tox.hxx> 44 #include <docsh.hxx> 45 46 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> 47 #include <com/sun/star/document/XDocumentProperties.hpp> 48 49 using namespace ::com::sun::star; 50 51 52 class CompareLine 53 { 54 public: 55 CompareLine() {} 56 virtual ~CompareLine(); 57 58 virtual sal_uLong GetHashValue() const = 0; 59 virtual sal_Bool Compare( const CompareLine& rLine ) const = 0; 60 }; 61 62 DECLARE_LIST( CompareList, CompareLine* ) 63 64 class CompareData 65 { 66 sal_uLong* pIndex; 67 sal_Bool* pChangedFlag; 68 69 protected: 70 CompareList aLines; 71 sal_uLong nSttLineNum; 72 73 // Anfang und Ende beschneiden und alle anderen in das 74 // LinesArray setzen 75 virtual void CheckRanges( CompareData& ) = 0; 76 77 public: 78 CompareData(); 79 virtual ~CompareData(); 80 81 // gibt es unterschiede? 82 sal_Bool HasDiffs( const CompareData& rData ) const; 83 84 // startet das Vergleichen und Erzeugen der Unterschiede zweier 85 // Dokumente 86 void CompareLines( CompareData& rData ); 87 // lasse die Unterschiede anzeigen - ruft die beiden Methoden 88 // ShowInsert / ShowDelete. Diese bekommen die Start und EndLine-Nummer 89 // uebergeben. Die Abbildung auf den tatsaechline Inhalt muss die 90 // Ableitung uebernehmen! 91 sal_uLong ShowDiffs( const CompareData& rData ); 92 93 virtual void ShowInsert( sal_uLong nStt, sal_uLong nEnd ); 94 virtual void ShowDelete( const CompareData& rData, sal_uLong nStt, 95 sal_uLong nEnd, sal_uLong nInsPos ); 96 virtual void CheckForChangesInLine( const CompareData& rData, 97 sal_uLong& nStt, sal_uLong& nEnd, 98 sal_uLong& nThisStt, sal_uLong& nThisEnd ); 99 100 // Eindeutigen Index fuer eine Line setzen. Gleiche Lines haben den 101 // selben Index; auch in den anderen CompareData! 102 void SetIndex( sal_uLong nLine, sal_uLong nIndex ); 103 sal_uLong GetIndex( sal_uLong nLine ) const 104 { return nLine < aLines.Count() ? pIndex[ nLine ] : 0; } 105 106 // setze/erfrage ob eine Zeile veraendert ist 107 void SetChanged( sal_uLong nLine, sal_Bool bFlag = sal_True ); 108 sal_Bool GetChanged( sal_uLong nLine ) const 109 { 110 return (pChangedFlag && nLine < aLines.Count()) 111 ? pChangedFlag[ nLine ] 112 : 0; 113 } 114 115 sal_uLong GetLineCount() const { return aLines.Count(); } 116 sal_uLong GetLineOffset() const { return nSttLineNum; } 117 const CompareLine* GetLine( sal_uLong nLine ) const 118 { return aLines.GetObject( nLine ); } 119 void InsertLine( CompareLine* pLine ) 120 { aLines.Insert( pLine, LIST_APPEND ); } 121 }; 122 123 class Hash 124 { 125 struct _HashData 126 { 127 sal_uLong nNext, nHash; 128 const CompareLine* pLine; 129 130 _HashData() 131 : nNext( 0 ), nHash( 0 ), pLine(0) {} 132 }; 133 134 sal_uLong* pHashArr; 135 _HashData* pDataArr; 136 sal_uLong nCount, nPrime; 137 138 public: 139 Hash( sal_uLong nSize ); 140 ~Hash(); 141 142 void CalcHashValue( CompareData& rData ); 143 144 sal_uLong GetCount() const { return nCount; } 145 }; 146 147 class Compare 148 { 149 public: 150 class MovedData 151 { 152 sal_uLong* pIndex; 153 sal_uLong* pLineNum; 154 sal_uLong nCount; 155 156 public: 157 MovedData( CompareData& rData, sal_Char* pDiscard ); 158 ~MovedData(); 159 160 sal_uLong GetIndex( sal_uLong n ) const { return pIndex[ n ]; } 161 sal_uLong GetLineNum( sal_uLong n ) const { return pLineNum[ n ]; } 162 sal_uLong GetCount() const { return nCount; } 163 }; 164 165 private: 166 // Suche die verschobenen Lines 167 class CompareSequence 168 { 169 CompareData &rData1, &rData2; 170 const MovedData &rMoved1, &rMoved2; 171 long *pMemory, *pFDiag, *pBDiag; 172 173 void Compare( sal_uLong nStt1, sal_uLong nEnd1, sal_uLong nStt2, sal_uLong nEnd2 ); 174 sal_uLong CheckDiag( sal_uLong nStt1, sal_uLong nEnd1, 175 sal_uLong nStt2, sal_uLong nEnd2, sal_uLong* pCost ); 176 public: 177 CompareSequence( CompareData& rData1, CompareData& rData2, 178 const MovedData& rD1, const MovedData& rD2 ); 179 ~CompareSequence(); 180 }; 181 182 183 static void CountDifference( const CompareData& rData, sal_uLong* pCounts ); 184 static void SetDiscard( const CompareData& rData, 185 sal_Char* pDiscard, sal_uLong* pCounts ); 186 static void CheckDiscard( sal_uLong nLen, sal_Char* pDiscard ); 187 static sal_uLong SetChangedFlag( CompareData& rData, sal_Char* pDiscard, int bFirst ); 188 static void ShiftBoundaries( CompareData& rData1, CompareData& rData2 ); 189 190 public: 191 Compare( sal_uLong nDiff, CompareData& rData1, CompareData& rData2 ); 192 }; 193 194 // ==================================================================== 195 196 CompareLine::~CompareLine() {} 197 198 // ---------------------------------------------------------------------- 199 200 CompareData::CompareData() 201 : pIndex( 0 ), pChangedFlag( 0 ), nSttLineNum( 0 ) 202 { 203 } 204 205 CompareData::~CompareData() 206 { 207 delete[] pIndex; 208 delete[] pChangedFlag; 209 } 210 211 void CompareData::SetIndex( sal_uLong nLine, sal_uLong nIndex ) 212 { 213 if( !pIndex ) 214 { 215 pIndex = new sal_uLong[ aLines.Count() ]; 216 memset( pIndex, 0, aLines.Count() * sizeof( sal_uLong ) ); 217 } 218 if( nLine < aLines.Count() ) 219 pIndex[ nLine ] = nIndex; 220 } 221 222 void CompareData::SetChanged( sal_uLong nLine, sal_Bool bFlag ) 223 { 224 if( !pChangedFlag ) 225 { 226 pChangedFlag = new sal_Bool[ aLines.Count() +1 ]; 227 memset( pChangedFlag, 0, aLines.Count() +1 * sizeof( sal_Bool ) ); 228 } 229 if( nLine < aLines.Count() ) 230 pChangedFlag[ nLine ] = bFlag; 231 } 232 233 void CompareData::CompareLines( CompareData& rData ) 234 { 235 CheckRanges( rData ); 236 237 sal_uLong nDifferent; 238 { 239 Hash aH( GetLineCount() + rData.GetLineCount() + 1 ); 240 aH.CalcHashValue( *this ); 241 aH.CalcHashValue( rData ); 242 nDifferent = aH.GetCount(); 243 } 244 { 245 Compare aComp( nDifferent, *this, rData ); 246 } 247 } 248 249 sal_uLong CompareData::ShowDiffs( const CompareData& rData ) 250 { 251 sal_uLong nLen1 = rData.GetLineCount(), nLen2 = GetLineCount(); 252 sal_uLong nStt1 = 0, nStt2 = 0; 253 sal_uLong nCnt = 0; 254 255 while( nStt1 < nLen1 || nStt2 < nLen2 ) 256 { 257 if( rData.GetChanged( nStt1 ) || GetChanged( nStt2 ) ) 258 { 259 sal_uLong nSav1 = nStt1, nSav2 = nStt2; 260 while( nStt1 < nLen1 && rData.GetChanged( nStt1 )) ++nStt1; 261 while( nStt2 < nLen2 && GetChanged( nStt2 )) ++nStt2; 262 263 // rData ist das Original, 264 // this ist das, in das die Veraenderungen sollen 265 if( nSav2 != nStt2 && nSav1 != nStt1 ) 266 CheckForChangesInLine( rData, nSav1, nStt1, nSav2, nStt2 ); 267 268 if( nSav2 != nStt2 ) 269 ShowInsert( nSav2, nStt2 ); 270 271 if( nSav1 != nStt1 ) 272 ShowDelete( rData, nSav1, nStt1, nStt2 ); 273 ++nCnt; 274 } 275 ++nStt1, ++nStt2; 276 } 277 return nCnt; 278 } 279 280 sal_Bool CompareData::HasDiffs( const CompareData& rData ) const 281 { 282 sal_Bool bRet = sal_False; 283 sal_uLong nLen1 = rData.GetLineCount(), nLen2 = GetLineCount(); 284 sal_uLong nStt1 = 0, nStt2 = 0; 285 286 while( nStt1 < nLen1 || nStt2 < nLen2 ) 287 { 288 if( rData.GetChanged( nStt1 ) || GetChanged( nStt2 ) ) 289 { 290 bRet = sal_True; 291 break; 292 } 293 ++nStt1, ++nStt2; 294 } 295 return bRet; 296 } 297 298 void CompareData::ShowInsert( sal_uLong, sal_uLong ) 299 { 300 } 301 302 void CompareData::ShowDelete( const CompareData&, sal_uLong, sal_uLong, sal_uLong ) 303 { 304 } 305 306 void CompareData::CheckForChangesInLine( const CompareData& , 307 sal_uLong&, sal_uLong&, sal_uLong&, sal_uLong& ) 308 { 309 } 310 311 // ---------------------------------------------------------------------- 312 313 Hash::Hash( sal_uLong nSize ) 314 : nCount( 1 ) 315 { 316 317 static const sal_uLong primes[] = 318 { 319 509, 320 1021, 321 2039, 322 4093, 323 8191, 324 16381, 325 32749, 326 65521, 327 131071, 328 262139, 329 524287, 330 1048573, 331 2097143, 332 4194301, 333 8388593, 334 16777213, 335 33554393, 336 67108859, /* Preposterously large . . . */ 337 134217689, 338 268435399, 339 536870909, 340 1073741789, 341 2147483647, 342 0 343 }; 344 int i; 345 346 pDataArr = new _HashData[ nSize ]; 347 pDataArr[0].nNext = 0; 348 pDataArr[0].nHash = 0, 349 pDataArr[0].pLine = 0; 350 351 for( i = 0; primes[i] < nSize / 3; i++) 352 if( !primes[i] ) 353 { 354 pHashArr = 0; 355 return; 356 } 357 nPrime = primes[ i ]; 358 pHashArr = new sal_uLong[ nPrime ]; 359 memset( pHashArr, 0, nPrime * sizeof( sal_uLong ) ); 360 } 361 362 Hash::~Hash() 363 { 364 delete[] pHashArr; 365 delete[] pDataArr; 366 } 367 368 void Hash::CalcHashValue( CompareData& rData ) 369 { 370 if( pHashArr ) 371 { 372 for( sal_uLong n = 0; n < rData.GetLineCount(); ++n ) 373 { 374 const CompareLine* pLine = rData.GetLine( n ); 375 ASSERT( pLine, "wo ist die Line?" ); 376 sal_uLong nH = pLine->GetHashValue(); 377 378 sal_uLong* pFound = &pHashArr[ nH % nPrime ]; 379 sal_uLong i; 380 for( i = *pFound; ; i = pDataArr[i].nNext ) 381 if( !i ) 382 { 383 i = nCount++; 384 pDataArr[i].nNext = *pFound; 385 pDataArr[i].nHash = nH; 386 pDataArr[i].pLine = pLine; 387 *pFound = i; 388 break; 389 } 390 else if( pDataArr[i].nHash == nH && 391 pDataArr[i].pLine->Compare( *pLine )) 392 break; 393 394 rData.SetIndex( n, i ); 395 } 396 } 397 } 398 399 // ---------------------------------------------------------------------- 400 401 Compare::Compare( sal_uLong nDiff, CompareData& rData1, CompareData& rData2 ) 402 { 403 MovedData *pMD1, *pMD2; 404 // Suche die unterschiedlichen Lines 405 { 406 sal_Char* pDiscard1 = new sal_Char[ rData1.GetLineCount() ]; 407 sal_Char* pDiscard2 = new sal_Char[ rData2.GetLineCount() ]; 408 409 sal_uLong* pCount1 = new sal_uLong[ nDiff ]; 410 sal_uLong* pCount2 = new sal_uLong[ nDiff ]; 411 memset( pCount1, 0, nDiff * sizeof( sal_uLong )); 412 memset( pCount2, 0, nDiff * sizeof( sal_uLong )); 413 414 // stelle fest, welche Indizies in den CompareData mehrfach vergeben wurden 415 CountDifference( rData1, pCount1 ); 416 CountDifference( rData2, pCount2 ); 417 418 // alle die jetzt nur einmal vorhanden sind, sind eingefuegt oder 419 // geloescht worden. Alle die im anderen auch vorhanden sind, sind 420 // verschoben worden 421 SetDiscard( rData1, pDiscard1, pCount2 ); 422 SetDiscard( rData2, pDiscard2, pCount1 ); 423 424 // die Arrays koennen wir wieder vergessen 425 delete [] pCount1; delete [] pCount2; 426 427 CheckDiscard( rData1.GetLineCount(), pDiscard1 ); 428 CheckDiscard( rData2.GetLineCount(), pDiscard2 ); 429 430 pMD1 = new MovedData( rData1, pDiscard1 ); 431 pMD2 = new MovedData( rData2, pDiscard2 ); 432 433 // die Arrays koennen wir wieder vergessen 434 delete [] pDiscard1; delete [] pDiscard2; 435 } 436 437 { 438 CompareSequence aTmp( rData1, rData2, *pMD1, *pMD2 ); 439 } 440 441 ShiftBoundaries( rData1, rData2 ); 442 443 delete pMD1; 444 delete pMD2; 445 } 446 447 448 449 void Compare::CountDifference( const CompareData& rData, sal_uLong* pCounts ) 450 { 451 sal_uLong nLen = rData.GetLineCount(); 452 for( sal_uLong n = 0; n < nLen; ++n ) 453 { 454 sal_uLong nIdx = rData.GetIndex( n ); 455 ++pCounts[ nIdx ]; 456 } 457 } 458 459 void Compare::SetDiscard( const CompareData& rData, 460 sal_Char* pDiscard, sal_uLong* pCounts ) 461 { 462 sal_uLong nLen = rData.GetLineCount(); 463 464 // berechne Max in Abhanegigkeit zur LineAnzahl 465 sal_uInt16 nMax = 5; 466 sal_uLong n; 467 468 for( n = nLen / 64; ( n = n >> 2 ) > 0; ) 469 nMax <<= 1; 470 471 for( n = 0; n < nLen; ++n ) 472 { 473 sal_uLong nIdx = rData.GetIndex( n ); 474 if( nIdx ) 475 { 476 nIdx = pCounts[ nIdx ]; 477 pDiscard[ n ] = !nIdx ? 1 : nIdx > nMax ? 2 : 0; 478 } 479 else 480 pDiscard[ n ] = 0; 481 } 482 } 483 484 void Compare::CheckDiscard( sal_uLong nLen, sal_Char* pDiscard ) 485 { 486 for( sal_uLong n = 0; n < nLen; ++n ) 487 { 488 if( 2 == pDiscard[ n ] ) 489 pDiscard[n] = 0; 490 else if( pDiscard[ n ] ) 491 { 492 sal_uLong j; 493 sal_uLong length; 494 sal_uLong provisional = 0; 495 496 /* Find end of this run of discardable lines. 497 Count how many are provisionally discardable. */ 498 for (j = n; j < nLen; j++) 499 { 500 if( !pDiscard[j] ) 501 break; 502 if( 2 == pDiscard[j] ) 503 ++provisional; 504 } 505 506 /* Cancel provisional discards at end, and shrink the run. */ 507 while( j > n && 2 == pDiscard[j - 1] ) 508 pDiscard[ --j ] = 0, --provisional; 509 510 /* Now we have the length of a run of discardable lines 511 whose first and last are not provisional. */ 512 length = j - n; 513 514 /* If 1/4 of the lines in the run are provisional, 515 cancel discarding of all provisional lines in the run. */ 516 if (provisional * 4 > length) 517 { 518 while (j > n) 519 if (pDiscard[--j] == 2) 520 pDiscard[j] = 0; 521 } 522 else 523 { 524 sal_uLong consec; 525 sal_uLong minimum = 1; 526 sal_uLong tem = length / 4; 527 528 /* MINIMUM is approximate square root of LENGTH/4. 529 A subrun of two or more provisionals can stand 530 when LENGTH is at least 16. 531 A subrun of 4 or more can stand when LENGTH >= 64. */ 532 while ((tem = tem >> 2) > 0) 533 minimum *= 2; 534 minimum++; 535 536 /* Cancel any subrun of MINIMUM or more provisionals 537 within the larger run. */ 538 for (j = 0, consec = 0; j < length; j++) 539 if (pDiscard[n + j] != 2) 540 consec = 0; 541 else if (minimum == ++consec) 542 /* Back up to start of subrun, to cancel it all. */ 543 j -= consec; 544 else if (minimum < consec) 545 pDiscard[n + j] = 0; 546 547 /* Scan from beginning of run 548 until we find 3 or more nonprovisionals in a row 549 or until the first nonprovisional at least 8 lines in. 550 Until that point, cancel any provisionals. */ 551 for (j = 0, consec = 0; j < length; j++) 552 { 553 if (j >= 8 && pDiscard[n + j] == 1) 554 break; 555 if (pDiscard[n + j] == 2) 556 consec = 0, pDiscard[n + j] = 0; 557 else if (pDiscard[n + j] == 0) 558 consec = 0; 559 else 560 consec++; 561 if (consec == 3) 562 break; 563 } 564 565 /* I advances to the last line of the run. */ 566 n += length - 1; 567 568 /* Same thing, from end. */ 569 for (j = 0, consec = 0; j < length; j++) 570 { 571 if (j >= 8 && pDiscard[n - j] == 1) 572 break; 573 if (pDiscard[n - j] == 2) 574 consec = 0, pDiscard[n - j] = 0; 575 else if (pDiscard[n - j] == 0) 576 consec = 0; 577 else 578 consec++; 579 if (consec == 3) 580 break; 581 } 582 } 583 } 584 } 585 } 586 587 // ---------------------------------------------------------------------- 588 589 Compare::MovedData::MovedData( CompareData& rData, sal_Char* pDiscard ) 590 : pIndex( 0 ), pLineNum( 0 ), nCount( 0 ) 591 { 592 sal_uLong nLen = rData.GetLineCount(); 593 sal_uLong n; 594 595 for( n = 0; n < nLen; ++n ) 596 if( pDiscard[ n ] ) 597 rData.SetChanged( n ); 598 else 599 ++nCount; 600 601 if( nCount ) 602 { 603 pIndex = new sal_uLong[ nCount ]; 604 pLineNum = new sal_uLong[ nCount ]; 605 606 for( n = 0, nCount = 0; n < nLen; ++n ) 607 if( !pDiscard[ n ] ) 608 { 609 pIndex[ nCount ] = rData.GetIndex( n ); 610 pLineNum[ nCount++ ] = n; 611 } 612 } 613 } 614 615 Compare::MovedData::~MovedData() 616 { 617 delete [] pIndex; 618 delete [] pLineNum; 619 } 620 621 // ---------------------------------------------------------------------- 622 623 // Suche die verschobenen Lines 624 Compare::CompareSequence::CompareSequence( 625 CompareData& rD1, CompareData& rD2, 626 const MovedData& rMD1, const MovedData& rMD2 ) 627 : rData1( rD1 ), rData2( rD2 ), rMoved1( rMD1 ), rMoved2( rMD2 ) 628 { 629 sal_uLong nSize = rMD1.GetCount() + rMD2.GetCount() + 3; 630 pMemory = new long[ nSize * 2 ]; 631 pFDiag = pMemory + ( rMD2.GetCount() + 1 ); 632 pBDiag = pMemory + ( nSize + rMD2.GetCount() + 1 ); 633 634 Compare( 0, rMD1.GetCount(), 0, rMD2.GetCount() ); 635 } 636 637 Compare::CompareSequence::~CompareSequence() 638 { 639 delete [] pMemory; 640 } 641 642 void Compare::CompareSequence::Compare( sal_uLong nStt1, sal_uLong nEnd1, 643 sal_uLong nStt2, sal_uLong nEnd2 ) 644 { 645 /* Slide down the bottom initial diagonal. */ 646 while( nStt1 < nEnd1 && nStt2 < nEnd2 && 647 rMoved1.GetIndex( nStt1 ) == rMoved2.GetIndex( nStt2 )) 648 ++nStt1, ++nStt2; 649 650 /* Slide up the top initial diagonal. */ 651 while( nEnd1 > nStt1 && nEnd2 > nStt2 && 652 rMoved1.GetIndex( nEnd1 - 1 ) == rMoved2.GetIndex( nEnd2 - 1 )) 653 --nEnd1, --nEnd2; 654 655 /* Handle simple cases. */ 656 if( nStt1 == nEnd1 ) 657 while( nStt2 < nEnd2 ) 658 rData2.SetChanged( rMoved2.GetLineNum( nStt2++ )); 659 660 else if (nStt2 == nEnd2) 661 while (nStt1 < nEnd1) 662 rData1.SetChanged( rMoved1.GetLineNum( nStt1++ )); 663 664 else 665 { 666 sal_uLong c, d, b; 667 668 /* Find a point of correspondence in the middle of the files. */ 669 670 d = CheckDiag( nStt1, nEnd1, nStt2, nEnd2, &c ); 671 b = pBDiag[ d ]; 672 673 if( 1 != c ) 674 { 675 /* Use that point to split this problem into two subproblems. */ 676 Compare( nStt1, b, nStt2, b - d ); 677 /* This used to use f instead of b, 678 but that is incorrect! 679 It is not necessarily the case that diagonal d 680 has a snake from b to f. */ 681 Compare( b, nEnd1, b - d, nEnd2 ); 682 } 683 } 684 } 685 686 sal_uLong Compare::CompareSequence::CheckDiag( sal_uLong nStt1, sal_uLong nEnd1, 687 sal_uLong nStt2, sal_uLong nEnd2, sal_uLong* pCost ) 688 { 689 const long dmin = nStt1 - nEnd2; /* Minimum valid diagonal. */ 690 const long dmax = nEnd1 - nStt2; /* Maximum valid diagonal. */ 691 const long fmid = nStt1 - nStt2; /* Center diagonal of top-down search. */ 692 const long bmid = nEnd1 - nEnd2; /* Center diagonal of bottom-up search. */ 693 694 long fmin = fmid, fmax = fmid; /* Limits of top-down search. */ 695 long bmin = bmid, bmax = bmid; /* Limits of bottom-up search. */ 696 697 long c; /* Cost. */ 698 long odd = (fmid - bmid) & 1; /* True if southeast corner is on an odd 699 diagonal with respect to the northwest. */ 700 701 pFDiag[fmid] = nStt1; 702 pBDiag[bmid] = nEnd1; 703 704 for (c = 1;; ++c) 705 { 706 long d; /* Active diagonal. */ 707 long big_snake = 0; 708 709 /* Extend the top-down search by an edit step in each diagonal. */ 710 fmin > dmin ? pFDiag[--fmin - 1] = -1 : ++fmin; 711 fmax < dmax ? pFDiag[++fmax + 1] = -1 : --fmax; 712 for (d = fmax; d >= fmin; d -= 2) 713 { 714 long x, y, oldx, tlo = pFDiag[d - 1], thi = pFDiag[d + 1]; 715 716 if (tlo >= thi) 717 x = tlo + 1; 718 else 719 x = thi; 720 oldx = x; 721 y = x - d; 722 while( sal_uLong(x) < nEnd1 && sal_uLong(y) < nEnd2 && 723 rMoved1.GetIndex( x ) == rMoved2.GetIndex( y )) 724 ++x, ++y; 725 if (x - oldx > 20) 726 big_snake = 1; 727 pFDiag[d] = x; 728 if( odd && bmin <= d && d <= bmax && pBDiag[d] <= pFDiag[d] ) 729 { 730 *pCost = 2 * c - 1; 731 return d; 732 } 733 } 734 735 /* Similar extend the bottom-up search. */ 736 bmin > dmin ? pBDiag[--bmin - 1] = INT_MAX : ++bmin; 737 bmax < dmax ? pBDiag[++bmax + 1] = INT_MAX : --bmax; 738 for (d = bmax; d >= bmin; d -= 2) 739 { 740 long x, y, oldx, tlo = pBDiag[d - 1], thi = pBDiag[d + 1]; 741 742 if (tlo < thi) 743 x = tlo; 744 else 745 x = thi - 1; 746 oldx = x; 747 y = x - d; 748 while( sal_uLong(x) > nStt1 && sal_uLong(y) > nStt2 && 749 rMoved1.GetIndex( x - 1 ) == rMoved2.GetIndex( y - 1 )) 750 --x, --y; 751 if (oldx - x > 20) 752 big_snake = 1; 753 pBDiag[d] = x; 754 if (!odd && fmin <= d && d <= fmax && pBDiag[d] <= pFDiag[d]) 755 { 756 *pCost = 2 * c; 757 return d; 758 } 759 } 760 } 761 } 762 763 void Compare::ShiftBoundaries( CompareData& rData1, CompareData& rData2 ) 764 { 765 for( int iz = 0; iz < 2; ++iz ) 766 { 767 CompareData* pData = &rData1; 768 CompareData* pOtherData = &rData2; 769 770 sal_uLong i = 0; 771 sal_uLong j = 0; 772 sal_uLong i_end = pData->GetLineCount(); 773 sal_uLong preceding = ULONG_MAX; 774 sal_uLong other_preceding = ULONG_MAX; 775 776 while (1) 777 { 778 sal_uLong start, other_start; 779 780 /* Scan forwards to find beginning of another run of changes. 781 Also keep track of the corresponding point in the other file. */ 782 783 while( i < i_end && !pData->GetChanged( i ) ) 784 { 785 while( pOtherData->GetChanged( j++ )) 786 /* Non-corresponding lines in the other file 787 will count as the preceding batch of changes. */ 788 other_preceding = j; 789 i++; 790 } 791 792 if (i == i_end) 793 break; 794 795 start = i; 796 other_start = j; 797 798 while (1) 799 { 800 /* Now find the end of this run of changes. */ 801 802 while( pData->GetChanged( ++i )) 803 ; 804 805 /* If the first changed line matches the following unchanged one, 806 and this run does not follow right after a previous run, 807 and there are no lines deleted from the other file here, 808 then classify the first changed line as unchanged 809 and the following line as changed in its place. */ 810 811 /* You might ask, how could this run follow right after another? 812 Only because the previous run was shifted here. */ 813 814 if( i != i_end && 815 pData->GetIndex( start ) == pData->GetIndex( i ) && 816 !pOtherData->GetChanged( j ) && 817 !( start == preceding || other_start == other_preceding )) 818 { 819 pData->SetChanged( start++, 0 ); 820 pData->SetChanged( i ); 821 /* Since one line-that-matches is now before this run 822 instead of after, we must advance in the other file 823 to keep in synch. */ 824 ++j; 825 } 826 else 827 break; 828 } 829 830 preceding = i; 831 other_preceding = j; 832 } 833 834 pData = &rData2; 835 pOtherData = &rData1; 836 } 837 } 838 839 /* */ 840 841 class SwCompareLine : public CompareLine 842 { 843 const SwNode& rNode; 844 public: 845 SwCompareLine( const SwNode& rNd ); 846 virtual ~SwCompareLine(); 847 848 virtual sal_uLong GetHashValue() const; 849 virtual sal_Bool Compare( const CompareLine& rLine ) const; 850 851 static sal_uLong GetTxtNodeHashValue( const SwTxtNode& rNd, sal_uLong nVal ); 852 static sal_Bool CompareNode( const SwNode& rDstNd, const SwNode& rSrcNd ); 853 static sal_Bool CompareTxtNd( const SwTxtNode& rDstNd, 854 const SwTxtNode& rSrcNd ); 855 856 sal_Bool ChangesInLine( const SwCompareLine& rLine, 857 SwPaM *& rpInsRing, SwPaM*& rpDelRing ) const; 858 859 const SwNode& GetNode() const { return rNode; } 860 861 const SwNode& GetEndNode() const; 862 863 // fuers Debugging! 864 String GetText() const; 865 }; 866 867 class SwCompareData : public CompareData 868 { 869 SwDoc& rDoc; 870 SwPaM *pInsRing, *pDelRing; 871 872 sal_uLong PrevIdx( const SwNode* pNd ); 873 sal_uLong NextIdx( const SwNode* pNd ); 874 875 virtual void CheckRanges( CompareData& ); 876 virtual void ShowInsert( sal_uLong nStt, sal_uLong nEnd ); 877 virtual void ShowDelete( const CompareData& rData, sal_uLong nStt, 878 sal_uLong nEnd, sal_uLong nInsPos ); 879 880 virtual void CheckForChangesInLine( const CompareData& rData, 881 sal_uLong& nStt, sal_uLong& nEnd, 882 sal_uLong& nThisStt, sal_uLong& nThisEnd ); 883 884 public: 885 SwCompareData( SwDoc& rD ) : rDoc( rD ), pInsRing(0), pDelRing(0) {} 886 virtual ~SwCompareData(); 887 888 void SetRedlinesToDoc( sal_Bool bUseDocInfo ); 889 }; 890 891 // ---------------------------------------------------------------- 892 893 SwCompareLine::SwCompareLine( const SwNode& rNd ) 894 : rNode( rNd ) 895 { 896 } 897 898 SwCompareLine::~SwCompareLine() 899 { 900 } 901 902 sal_uLong SwCompareLine::GetHashValue() const 903 { 904 sal_uLong nRet = 0; 905 switch( rNode.GetNodeType() ) 906 { 907 case ND_TEXTNODE: 908 nRet = GetTxtNodeHashValue( (SwTxtNode&)rNode, nRet ); 909 break; 910 911 case ND_TABLENODE: 912 { 913 const SwNode* pEndNd = rNode.EndOfSectionNode(); 914 SwNodeIndex aIdx( rNode ); 915 while( &aIdx.GetNode() != pEndNd ) 916 { 917 if( aIdx.GetNode().IsTxtNode() ) 918 nRet = GetTxtNodeHashValue( (SwTxtNode&)aIdx.GetNode(), nRet ); 919 aIdx++; 920 } 921 } 922 break; 923 924 case ND_SECTIONNODE: 925 { 926 String sStr( GetText() ); 927 for( xub_StrLen n = 0; n < sStr.Len(); ++n ) 928 ( nRet <<= 1 ) += sStr.GetChar( n ); 929 } 930 break; 931 932 case ND_GRFNODE: 933 case ND_OLENODE: 934 // feste Id ? sollte aber nie auftauchen 935 break; 936 } 937 return nRet; 938 } 939 940 const SwNode& SwCompareLine::GetEndNode() const 941 { 942 const SwNode* pNd = &rNode; 943 switch( rNode.GetNodeType() ) 944 { 945 case ND_TABLENODE: 946 pNd = rNode.EndOfSectionNode(); 947 break; 948 949 case ND_SECTIONNODE: 950 { 951 const SwSectionNode& rSNd = (SwSectionNode&)rNode; 952 const SwSection& rSect = rSNd.GetSection(); 953 if( CONTENT_SECTION != rSect.GetType() || rSect.IsProtect() ) 954 pNd = rNode.EndOfSectionNode(); 955 } 956 break; 957 } 958 return *pNd; 959 } 960 961 sal_Bool SwCompareLine::Compare( const CompareLine& rLine ) const 962 { 963 return CompareNode( rNode, ((SwCompareLine&)rLine).rNode ); 964 } 965 966 namespace 967 { 968 static String SimpleTableToText(const SwNode &rNode) 969 { 970 String sRet; 971 const SwNode* pEndNd = rNode.EndOfSectionNode(); 972 SwNodeIndex aIdx( rNode ); 973 while (&aIdx.GetNode() != pEndNd) 974 { 975 if (aIdx.GetNode().IsTxtNode()) 976 { 977 if (sRet.Len()) 978 { 979 sRet.Append( '\n' ); 980 } 981 sRet.Append( aIdx.GetNode().GetTxtNode()->GetExpandTxt() ); 982 } 983 aIdx++; 984 } 985 return sRet; 986 } 987 } 988 989 sal_Bool SwCompareLine::CompareNode( const SwNode& rDstNd, const SwNode& rSrcNd ) 990 { 991 if( rSrcNd.GetNodeType() != rDstNd.GetNodeType() ) 992 return sal_False; 993 994 sal_Bool bRet = sal_False; 995 996 switch( rDstNd.GetNodeType() ) 997 { 998 case ND_TEXTNODE: 999 bRet = CompareTxtNd( (SwTxtNode&)rDstNd, (SwTxtNode&)rSrcNd ); 1000 break; 1001 1002 case ND_TABLENODE: 1003 { 1004 const SwTableNode& rTSrcNd = (SwTableNode&)rSrcNd; 1005 const SwTableNode& rTDstNd = (SwTableNode&)rDstNd; 1006 1007 bRet = ( rTSrcNd.EndOfSectionIndex() - rTSrcNd.GetIndex() ) == 1008 ( rTDstNd.EndOfSectionIndex() - rTDstNd.GetIndex() ); 1009 1010 // --> #i107826#: compare actual table content 1011 if (bRet) 1012 { 1013 bRet = (SimpleTableToText(rSrcNd) == SimpleTableToText(rDstNd)); 1014 } 1015 // <-- 1016 } 1017 break; 1018 1019 case ND_SECTIONNODE: 1020 { 1021 const SwSectionNode& rSSrcNd = (SwSectionNode&)rSrcNd, 1022 & rSDstNd = (SwSectionNode&)rDstNd; 1023 const SwSection& rSrcSect = rSSrcNd.GetSection(), 1024 & rDstSect = rSDstNd.GetSection(); 1025 SectionType eSrcSectType = rSrcSect.GetType(), 1026 eDstSectType = rDstSect.GetType(); 1027 switch( eSrcSectType ) 1028 { 1029 case CONTENT_SECTION: 1030 bRet = CONTENT_SECTION == eDstSectType && 1031 rSrcSect.IsProtect() == rDstSect.IsProtect(); 1032 if( bRet && rSrcSect.IsProtect() ) 1033 { 1034 // the only have they both the same size 1035 bRet = ( rSSrcNd.EndOfSectionIndex() - rSSrcNd.GetIndex() ) == 1036 ( rSDstNd.EndOfSectionIndex() - rSDstNd.GetIndex() ); 1037 } 1038 break; 1039 1040 case TOX_HEADER_SECTION: 1041 case TOX_CONTENT_SECTION: 1042 if( TOX_HEADER_SECTION == eDstSectType || 1043 TOX_CONTENT_SECTION == eDstSectType ) 1044 { 1045 // the same type of TOX? 1046 const SwTOXBase* pSrcTOX = rSrcSect.GetTOXBase(); 1047 const SwTOXBase* pDstTOX = rDstSect.GetTOXBase(); 1048 bRet = pSrcTOX && pDstTOX 1049 && pSrcTOX->GetType() == pDstTOX->GetType() 1050 && pSrcTOX->GetTitle() == pDstTOX->GetTitle() 1051 && pSrcTOX->GetTypeName() == pDstTOX->GetTypeName() 1052 // && pSrcTOX->GetTOXName() == pDstTOX->GetTOXName() 1053 ; 1054 } 1055 break; 1056 1057 case DDE_LINK_SECTION: 1058 case FILE_LINK_SECTION: 1059 bRet = eSrcSectType == eDstSectType && 1060 rSrcSect.GetLinkFileName() == 1061 rDstSect.GetLinkFileName(); 1062 break; 1063 } 1064 } 1065 break; 1066 1067 case ND_ENDNODE: 1068 bRet = rSrcNd.StartOfSectionNode()->GetNodeType() == 1069 rDstNd.StartOfSectionNode()->GetNodeType(); 1070 1071 // --> #i107826#: compare actual table content 1072 if (bRet && rSrcNd.StartOfSectionNode()->GetNodeType() == ND_TABLENODE) 1073 { 1074 bRet = CompareNode( 1075 *rSrcNd.StartOfSectionNode(), *rDstNd.StartOfSectionNode()); 1076 } 1077 // <-- 1078 1079 break; 1080 } 1081 return bRet; 1082 } 1083 1084 String SwCompareLine::GetText() const 1085 { 1086 String sRet; 1087 switch( rNode.GetNodeType() ) 1088 { 1089 case ND_TEXTNODE: 1090 sRet = ((SwTxtNode&)rNode).GetExpandTxt(); 1091 break; 1092 1093 case ND_TABLENODE: 1094 { 1095 sRet = SimpleTableToText(rNode); 1096 sRet.InsertAscii( "Tabelle: ", 0 ); 1097 } 1098 break; 1099 1100 case ND_SECTIONNODE: 1101 { 1102 sRet.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "Section - Node:" )); 1103 1104 const SwSectionNode& rSNd = (SwSectionNode&)rNode; 1105 const SwSection& rSect = rSNd.GetSection(); 1106 switch( rSect.GetType() ) 1107 { 1108 case CONTENT_SECTION: 1109 if( rSect.IsProtect() ) 1110 sRet.Append( String::CreateFromInt32( 1111 rSNd.EndOfSectionIndex() - rSNd.GetIndex() )); 1112 break; 1113 1114 case TOX_HEADER_SECTION: 1115 case TOX_CONTENT_SECTION: 1116 { 1117 const SwTOXBase* pTOX = rSect.GetTOXBase(); 1118 if( pTOX ) 1119 sRet.Append( pTOX->GetTitle() ) 1120 .Append( pTOX->GetTypeName() ) 1121 // .Append( pTOX->GetTOXName() ) 1122 .Append( String::CreateFromInt32( pTOX->GetType() )); 1123 } 1124 break; 1125 1126 case DDE_LINK_SECTION: 1127 case FILE_LINK_SECTION: 1128 sRet += rSect.GetLinkFileName(); 1129 break; 1130 } 1131 } 1132 break; 1133 1134 case ND_GRFNODE: 1135 sRet.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "Grafik - Node:" )); 1136 break; 1137 case ND_OLENODE: 1138 sRet.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "OLE - Node:" )); 1139 break; 1140 } 1141 return sRet; 1142 } 1143 1144 sal_uLong SwCompareLine::GetTxtNodeHashValue( const SwTxtNode& rNd, sal_uLong nVal ) 1145 { 1146 String sStr( rNd.GetExpandTxt() ); 1147 for( xub_StrLen n = 0; n < sStr.Len(); ++n ) 1148 ( nVal <<= 1 ) += sStr.GetChar( n ); 1149 return nVal; 1150 } 1151 1152 sal_Bool SwCompareLine::CompareTxtNd( const SwTxtNode& rDstNd, 1153 const SwTxtNode& rSrcNd ) 1154 { 1155 sal_Bool bRet = sal_False; 1156 // erstmal ganz einfach! 1157 if( rDstNd.GetTxt() == rSrcNd.GetTxt() ) 1158 { 1159 // der Text ist gleich, aber sind die "Sonderattribute" (0xFF) auch 1160 // dieselben?? 1161 bRet = sal_True; 1162 } 1163 return bRet; 1164 } 1165 1166 sal_Bool SwCompareLine::ChangesInLine( const SwCompareLine& rLine, 1167 SwPaM *& rpInsRing, SwPaM*& rpDelRing ) const 1168 { 1169 sal_Bool bRet = sal_False; 1170 if( ND_TEXTNODE == rNode.GetNodeType() && 1171 ND_TEXTNODE == rLine.GetNode().GetNodeType() ) 1172 { 1173 SwTxtNode& rDestNd = *(SwTxtNode*)rNode.GetTxtNode(); 1174 const SwTxtNode& rSrcNd = *rLine.GetNode().GetTxtNode(); 1175 1176 xub_StrLen nDEnd = rDestNd.GetTxt().Len(), nSEnd = rSrcNd.GetTxt().Len(); 1177 xub_StrLen nStt; 1178 xub_StrLen nEnd; 1179 1180 for( nStt = 0, nEnd = Min( nDEnd, nSEnd ); nStt < nEnd; ++nStt ) 1181 if( rDestNd.GetTxt().GetChar( nStt ) != 1182 rSrcNd.GetTxt().GetChar( nStt ) ) 1183 break; 1184 1185 while( nStt < nDEnd && nStt < nSEnd ) 1186 { 1187 --nDEnd, --nSEnd; 1188 if( rDestNd.GetTxt().GetChar( nDEnd ) != 1189 rSrcNd.GetTxt().GetChar( nSEnd ) ) 1190 { 1191 ++nDEnd, ++nSEnd; 1192 break; 1193 } 1194 } 1195 1196 if( nStt || !nDEnd || !nSEnd || nDEnd < rDestNd.GetTxt().Len() || 1197 nSEnd < rSrcNd.GetTxt().Len() ) 1198 { 1199 // jetzt ist zwischen nStt bis nDEnd das neu eingefuegte 1200 // und zwischen nStt und nSEnd das geloeschte 1201 SwDoc* pDoc = rDestNd.GetDoc(); 1202 SwPaM aPam( rDestNd, nDEnd ); 1203 if( nStt != nDEnd ) 1204 { 1205 SwPaM* pTmp = new SwPaM( *aPam.GetPoint(), rpInsRing ); 1206 if( !rpInsRing ) 1207 rpInsRing = pTmp; 1208 1209 pTmp->SetMark(); 1210 pTmp->GetMark()->nContent = nStt; 1211 } 1212 1213 if( nStt != nSEnd ) 1214 { 1215 { 1216 ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo()); 1217 SwPaM aCpyPam( rSrcNd, nStt ); 1218 aCpyPam.SetMark(); 1219 aCpyPam.GetPoint()->nContent = nSEnd; 1220 aCpyPam.GetDoc()->CopyRange( aCpyPam, *aPam.GetPoint(), 1221 false ); 1222 } 1223 1224 SwPaM* pTmp = new SwPaM( *aPam.GetPoint(), rpDelRing ); 1225 if( !rpDelRing ) 1226 rpDelRing = pTmp; 1227 1228 pTmp->SetMark(); 1229 pTmp->GetMark()->nContent = nDEnd; 1230 1231 if( rpInsRing ) 1232 { 1233 SwPaM* pCorr = (SwPaM*)rpInsRing->GetPrev(); 1234 if( *pCorr->GetPoint() == *pTmp->GetPoint() ) 1235 *pCorr->GetPoint() = *pTmp->GetMark(); 1236 } 1237 } 1238 bRet = sal_True; 1239 } 1240 } 1241 return bRet; 1242 } 1243 1244 // ---------------------------------------------------------------- 1245 1246 SwCompareData::~SwCompareData() 1247 { 1248 if( pDelRing ) 1249 { 1250 while( pDelRing->GetNext() != pDelRing ) 1251 delete pDelRing->GetNext(); 1252 delete pDelRing; 1253 } 1254 if( pInsRing ) 1255 { 1256 while( pInsRing->GetNext() != pInsRing ) 1257 delete pInsRing->GetNext(); 1258 delete pInsRing; 1259 } 1260 } 1261 1262 sal_uLong SwCompareData::NextIdx( const SwNode* pNd ) 1263 { 1264 if( pNd->IsStartNode() ) 1265 { 1266 const SwSectionNode* pSNd; 1267 if( pNd->IsTableNode() || 1268 ( 0 != (pSNd = pNd->GetSectionNode() ) && 1269 ( CONTENT_SECTION != pSNd->GetSection().GetType() || 1270 pSNd->GetSection().IsProtect() ) ) ) 1271 pNd = pNd->EndOfSectionNode(); 1272 } 1273 return pNd->GetIndex() + 1; 1274 } 1275 1276 sal_uLong SwCompareData::PrevIdx( const SwNode* pNd ) 1277 { 1278 if( pNd->IsEndNode() ) 1279 { 1280 const SwSectionNode* pSNd; 1281 if( pNd->StartOfSectionNode()->IsTableNode() || 1282 ( 0 != (pSNd = pNd->StartOfSectionNode()->GetSectionNode() ) && 1283 ( CONTENT_SECTION != pSNd->GetSection().GetType() || 1284 pSNd->GetSection().IsProtect() ) ) ) 1285 pNd = pNd->StartOfSectionNode(); 1286 } 1287 return pNd->GetIndex() - 1; 1288 } 1289 1290 1291 void SwCompareData::CheckRanges( CompareData& rData ) 1292 { 1293 const SwNodes& rSrcNds = ((SwCompareData&)rData).rDoc.GetNodes(); 1294 const SwNodes& rDstNds = rDoc.GetNodes(); 1295 1296 const SwNode& rSrcEndNd = rSrcNds.GetEndOfContent(); 1297 const SwNode& rDstEndNd = rDstNds.GetEndOfContent(); 1298 1299 sal_uLong nSrcSttIdx = NextIdx( rSrcEndNd.StartOfSectionNode() ); 1300 sal_uLong nSrcEndIdx = rSrcEndNd.GetIndex(); 1301 1302 sal_uLong nDstSttIdx = NextIdx( rDstEndNd.StartOfSectionNode() ); 1303 sal_uLong nDstEndIdx = rDstEndNd.GetIndex(); 1304 1305 while( nSrcSttIdx < nSrcEndIdx && nDstSttIdx < nDstEndIdx ) 1306 { 1307 const SwNode* pSrcNd = rSrcNds[ nSrcSttIdx ]; 1308 const SwNode* pDstNd = rDstNds[ nDstSttIdx ]; 1309 if( !SwCompareLine::CompareNode( *pSrcNd, *pDstNd )) 1310 break; 1311 1312 nSrcSttIdx = NextIdx( pSrcNd ); 1313 nDstSttIdx = NextIdx( pDstNd ); 1314 } 1315 1316 nSrcEndIdx = PrevIdx( &rSrcEndNd ); 1317 nDstEndIdx = PrevIdx( &rDstEndNd ); 1318 while( nSrcSttIdx < nSrcEndIdx && nDstSttIdx < nDstEndIdx ) 1319 { 1320 const SwNode* pSrcNd = rSrcNds[ nSrcEndIdx ]; 1321 const SwNode* pDstNd = rDstNds[ nDstEndIdx ]; 1322 if( !SwCompareLine::CompareNode( *pSrcNd, *pDstNd )) 1323 break; 1324 1325 nSrcEndIdx = PrevIdx( pSrcNd ); 1326 nDstEndIdx = PrevIdx( pDstNd ); 1327 } 1328 1329 while( nSrcSttIdx <= nSrcEndIdx ) 1330 { 1331 const SwNode* pNd = rSrcNds[ nSrcSttIdx ]; 1332 rData.InsertLine( new SwCompareLine( *pNd ) ); 1333 nSrcSttIdx = NextIdx( pNd ); 1334 } 1335 1336 while( nDstSttIdx <= nDstEndIdx ) 1337 { 1338 const SwNode* pNd = rDstNds[ nDstSttIdx ]; 1339 InsertLine( new SwCompareLine( *pNd ) ); 1340 nDstSttIdx = NextIdx( pNd ); 1341 } 1342 } 1343 1344 1345 void SwCompareData::ShowInsert( sal_uLong nStt, sal_uLong nEnd ) 1346 { 1347 SwPaM* pTmp = new SwPaM( ((SwCompareLine*)GetLine( nStt ))->GetNode(), 0, 1348 ((SwCompareLine*)GetLine( nEnd-1 ))->GetEndNode(), 0, 1349 pInsRing ); 1350 if( !pInsRing ) 1351 pInsRing = pTmp; 1352 1353 // #i65201#: These SwPaMs are calculated smaller than needed, see comment below 1354 1355 } 1356 1357 void SwCompareData::ShowDelete( const CompareData& rData, sal_uLong nStt, 1358 sal_uLong nEnd, sal_uLong nInsPos ) 1359 { 1360 SwNodeRange aRg( 1361 ((SwCompareLine*)rData.GetLine( nStt ))->GetNode(), 0, 1362 ((SwCompareLine*)rData.GetLine( nEnd-1 ))->GetEndNode(), 1 ); 1363 1364 sal_uInt16 nOffset = 0; 1365 const CompareLine* pLine; 1366 if( GetLineCount() == nInsPos ) 1367 { 1368 pLine = GetLine( nInsPos-1 ); 1369 nOffset = 1; 1370 } 1371 else 1372 pLine = GetLine( nInsPos ); 1373 1374 const SwNode* pLineNd; 1375 if( pLine ) 1376 { 1377 if( nOffset ) 1378 pLineNd = &((SwCompareLine*)pLine)->GetEndNode(); 1379 else 1380 pLineNd = &((SwCompareLine*)pLine)->GetNode(); 1381 } 1382 else 1383 { 1384 pLineNd = &rDoc.GetNodes().GetEndOfContent(); 1385 nOffset = 0; 1386 } 1387 1388 SwNodeIndex aInsPos( *pLineNd, nOffset ); 1389 SwNodeIndex aSavePos( aInsPos, -1 ); 1390 1391 ((SwCompareData&)rData).rDoc.CopyWithFlyInFly( aRg, 0, aInsPos ); 1392 rDoc.SetModified(); 1393 aSavePos++; 1394 1395 // #i65201#: These SwPaMs are calculated when the (old) delete-redlines are hidden, 1396 // they will be inserted when the delete-redlines are shown again. 1397 // To avoid unwanted insertions of delete-redlines into these new redlines, what happens 1398 // especially at the end of the document, I reduce the SwPaM by one node. 1399 // Before the new redlines are inserted, they have to expand again. 1400 SwPaM* pTmp = new SwPaM( aSavePos.GetNode(), aInsPos.GetNode(), 0, -1, pDelRing ); 1401 if( !pDelRing ) 1402 pDelRing = pTmp; 1403 1404 if( pInsRing ) 1405 { 1406 SwPaM* pCorr = (SwPaM*)pInsRing->GetPrev(); 1407 if( *pCorr->GetPoint() == *pTmp->GetPoint() ) 1408 { 1409 SwNodeIndex aTmpPos( pTmp->GetMark()->nNode, -1 ); 1410 *pCorr->GetPoint() = SwPosition( aTmpPos ); 1411 } 1412 } 1413 } 1414 1415 void SwCompareData::CheckForChangesInLine( const CompareData& rData, 1416 sal_uLong& rStt, sal_uLong& rEnd, 1417 sal_uLong& rThisStt, sal_uLong& rThisEnd ) 1418 { 1419 while( rStt < rEnd && rThisStt < rThisEnd ) 1420 { 1421 SwCompareLine* pDstLn = (SwCompareLine*)GetLine( rThisStt ); 1422 SwCompareLine* pSrcLn = (SwCompareLine*)rData.GetLine( rStt ); 1423 if( !pDstLn->ChangesInLine( *pSrcLn, pInsRing, pDelRing ) ) 1424 break; 1425 1426 ++rStt; 1427 ++rThisStt; 1428 } 1429 } 1430 1431 void SwCompareData::SetRedlinesToDoc( sal_Bool bUseDocInfo ) 1432 { 1433 SwPaM* pTmp = pDelRing; 1434 1435 // Bug #83296#: get the Author / TimeStamp from the "other" 1436 // document info 1437 sal_uInt16 nAuthor = rDoc.GetRedlineAuthor(); 1438 DateTime aTimeStamp; 1439 SwDocShell *pDocShell(rDoc.GetDocShell()); 1440 DBG_ASSERT(pDocShell, "no SwDocShell"); 1441 if (pDocShell) { 1442 uno::Reference<document::XDocumentPropertiesSupplier> xDPS( 1443 pDocShell->GetModel(), uno::UNO_QUERY_THROW); 1444 uno::Reference<document::XDocumentProperties> xDocProps( 1445 xDPS->getDocumentProperties()); 1446 DBG_ASSERT(xDocProps.is(), "Doc has no DocumentProperties"); 1447 1448 if( bUseDocInfo && xDocProps.is() ) { 1449 String aTmp( 1 == xDocProps->getEditingCycles() 1450 ? xDocProps->getAuthor() 1451 : xDocProps->getModifiedBy() ); 1452 util::DateTime uDT( 1 == xDocProps->getEditingCycles() 1453 ? xDocProps->getCreationDate() 1454 : xDocProps->getModificationDate() ); 1455 Date d(uDT.Day, uDT.Month, uDT.Year); 1456 Time t(uDT.Hours, uDT.Minutes, uDT.Seconds, uDT.HundredthSeconds); 1457 DateTime aDT(d,t); 1458 1459 if( aTmp.Len() ) 1460 { 1461 nAuthor = rDoc.InsertRedlineAuthor( aTmp ); 1462 aTimeStamp = aDT; 1463 } 1464 } 1465 } 1466 1467 if( pTmp ) 1468 { 1469 SwRedlineData aRedlnData( nsRedlineType_t::REDLINE_DELETE, nAuthor, aTimeStamp, 1470 aEmptyStr, 0, 0 ); 1471 do { 1472 // #i65201#: Expand again, see comment above. 1473 if( pTmp->GetPoint()->nContent == 0 ) 1474 { 1475 pTmp->GetPoint()->nNode++; 1476 pTmp->GetPoint()->nContent.Assign( pTmp->GetCntntNode(), 0 ); 1477 } 1478 // --> mst 2010-05-17 #i101009# 1479 // prevent redlines that end on structural end node 1480 if (& rDoc.GetNodes().GetEndOfContent() == 1481 & pTmp->GetPoint()->nNode.GetNode()) 1482 { 1483 pTmp->GetPoint()->nNode--; 1484 SwCntntNode *const pContentNode( pTmp->GetCntntNode() ); 1485 pTmp->GetPoint()->nContent.Assign( pContentNode, 1486 (pContentNode) ? pContentNode->Len() : 0 ); 1487 } 1488 // <-- 1489 1490 rDoc.DeleteRedline( *pTmp, false, USHRT_MAX ); 1491 1492 if (rDoc.GetIDocumentUndoRedo().DoesUndo()) 1493 { 1494 SwUndo *const pUndo(new SwUndoCompDoc( *pTmp, sal_False )) ; 1495 rDoc.GetIDocumentUndoRedo().AppendUndo(pUndo); 1496 } 1497 rDoc.AppendRedline( new SwRedline( aRedlnData, *pTmp ), true ); 1498 1499 } while( pDelRing != ( pTmp = (SwPaM*)pTmp->GetNext() )); 1500 } 1501 1502 pTmp = pInsRing; 1503 if( pTmp ) 1504 { 1505 do { 1506 if( pTmp->GetPoint()->nContent == 0 ) 1507 { 1508 pTmp->GetPoint()->nNode++; 1509 pTmp->GetPoint()->nContent.Assign( pTmp->GetCntntNode(), 0 ); 1510 } 1511 // --> mst 2010-05-17 #i101009# 1512 // prevent redlines that end on structural end node 1513 if (& rDoc.GetNodes().GetEndOfContent() == 1514 & pTmp->GetPoint()->nNode.GetNode()) 1515 { 1516 pTmp->GetPoint()->nNode--; 1517 SwCntntNode *const pContentNode( pTmp->GetCntntNode() ); 1518 pTmp->GetPoint()->nContent.Assign( pContentNode, 1519 (pContentNode) ? pContentNode->Len() : 0 ); 1520 } 1521 // <-- 1522 } while( pInsRing != ( pTmp = (SwPaM*)pTmp->GetNext() )); 1523 SwRedlineData aRedlnData( nsRedlineType_t::REDLINE_INSERT, nAuthor, aTimeStamp, 1524 aEmptyStr, 0, 0 ); 1525 1526 // zusammenhaengende zusammenfassen 1527 if( pTmp->GetNext() != pInsRing ) 1528 { 1529 const SwCntntNode* pCNd; 1530 do { 1531 SwPosition& rSttEnd = *pTmp->End(), 1532 & rEndStt = *((SwPaM*)pTmp->GetNext())->Start(); 1533 if( rSttEnd == rEndStt || 1534 (!rEndStt.nContent.GetIndex() && 1535 rEndStt.nNode.GetIndex() - 1 == rSttEnd.nNode.GetIndex() && 1536 0 != ( pCNd = rSttEnd.nNode.GetNode().GetCntntNode() ) 1537 ? rSttEnd.nContent.GetIndex() == pCNd->Len() 1538 : 0 )) 1539 { 1540 if( pTmp->GetNext() == pInsRing ) 1541 { 1542 // liegen hintereinander also zusammen fassen 1543 rEndStt = *pTmp->Start(); 1544 delete pTmp; 1545 pTmp = pInsRing; 1546 } 1547 else 1548 { 1549 // liegen hintereinander also zusammen fassen 1550 rSttEnd = *((SwPaM*)pTmp->GetNext())->End(); 1551 delete pTmp->GetNext(); 1552 } 1553 } 1554 else 1555 pTmp = (SwPaM*)pTmp->GetNext(); 1556 } while( pInsRing != pTmp ); 1557 } 1558 1559 do { 1560 if( rDoc.AppendRedline( new SwRedline( aRedlnData, *pTmp ), true) && 1561 rDoc.GetIDocumentUndoRedo().DoesUndo()) 1562 { 1563 SwUndo *const pUndo(new SwUndoCompDoc( *pTmp, sal_True )); 1564 rDoc.GetIDocumentUndoRedo().AppendUndo(pUndo); 1565 } 1566 } while( pInsRing != ( pTmp = (SwPaM*)pTmp->GetNext() )); 1567 } 1568 } 1569 1570 /* */ 1571 1572 1573 1574 // returnt (?die Anzahl der Unterschiede?) ob etwas unterschiedlich ist 1575 long SwDoc::CompareDoc( const SwDoc& rDoc ) 1576 { 1577 if( &rDoc == this ) 1578 return 0; 1579 1580 long nRet = 0; 1581 1582 GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL); 1583 sal_Bool bDocWasModified = IsModified(); 1584 SwDoc& rSrcDoc = (SwDoc&)rDoc; 1585 sal_Bool bSrcModified = rSrcDoc.IsModified(); 1586 1587 RedlineMode_t eSrcRedlMode = rSrcDoc.GetRedlineMode(); 1588 rSrcDoc.SetRedlineMode( nsRedlineMode_t::REDLINE_SHOW_INSERT ); 1589 SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT)); 1590 1591 SwCompareData aD0( rSrcDoc ); 1592 SwCompareData aD1( *this ); 1593 1594 aD1.CompareLines( aD0 ); 1595 1596 nRet = aD1.ShowDiffs( aD0 ); 1597 1598 if( nRet ) 1599 { 1600 SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | 1601 nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE)); 1602 1603 aD1.SetRedlinesToDoc( !bDocWasModified ); 1604 SetModified(); 1605 } 1606 1607 rSrcDoc.SetRedlineMode( eSrcRedlMode ); 1608 SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE)); 1609 1610 if( !bSrcModified ) 1611 rSrcDoc.ResetModified(); 1612 1613 GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL); 1614 1615 return nRet; 1616 } 1617 1618 1619 class _SaveMergeRedlines : public Ring 1620 { 1621 const SwRedline* pSrcRedl; 1622 SwRedline* pDestRedl; 1623 public: 1624 _SaveMergeRedlines( const SwNode& rDstNd, 1625 const SwRedline& rSrcRedl, Ring* pRing ); 1626 sal_uInt16 InsertRedline(); 1627 1628 SwRedline* GetDestRedline() { return pDestRedl; } 1629 }; 1630 1631 _SaveMergeRedlines::_SaveMergeRedlines( const SwNode& rDstNd, 1632 const SwRedline& rSrcRedl, Ring* pRing ) 1633 : Ring( pRing ), pSrcRedl( &rSrcRedl ) 1634 { 1635 SwPosition aPos( rDstNd ); 1636 1637 const SwPosition* pStt = rSrcRedl.Start(); 1638 if( rDstNd.IsCntntNode() ) 1639 aPos.nContent.Assign( ((SwCntntNode*)&rDstNd), pStt->nContent.GetIndex() ); 1640 pDestRedl = new SwRedline( rSrcRedl.GetRedlineData(), aPos ); 1641 1642 if( nsRedlineType_t::REDLINE_DELETE == pDestRedl->GetType() ) 1643 { 1644 // den Bereich als geloescht kennzeichnen 1645 const SwPosition* pEnd = pStt == rSrcRedl.GetPoint() 1646 ? rSrcRedl.GetMark() 1647 : rSrcRedl.GetPoint(); 1648 1649 pDestRedl->SetMark(); 1650 pDestRedl->GetPoint()->nNode += pEnd->nNode.GetIndex() - 1651 pStt->nNode.GetIndex(); 1652 pDestRedl->GetPoint()->nContent.Assign( pDestRedl->GetCntntNode(), 1653 pEnd->nContent.GetIndex() ); 1654 } 1655 } 1656 1657 sal_uInt16 _SaveMergeRedlines::InsertRedline() 1658 { 1659 sal_uInt16 nIns = 0; 1660 SwDoc* pDoc = pDestRedl->GetDoc(); 1661 1662 if( nsRedlineType_t::REDLINE_INSERT == pDestRedl->GetType() ) 1663 { 1664 // der Teil wurde eingefuegt, also kopiere ihn aus dem SourceDoc 1665 ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); 1666 1667 SwNodeIndex aSaveNd( pDestRedl->GetPoint()->nNode, -1 ); 1668 xub_StrLen nSaveCnt = pDestRedl->GetPoint()->nContent.GetIndex(); 1669 1670 RedlineMode_t eOld = pDoc->GetRedlineMode(); 1671 pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE)); 1672 1673 pSrcRedl->GetDoc()->CopyRange( 1674 *const_cast<SwPaM*>(static_cast<const SwPaM*>(pSrcRedl)), 1675 *pDestRedl->GetPoint(), false ); 1676 1677 pDoc->SetRedlineMode_intern( eOld ); 1678 1679 pDestRedl->SetMark(); 1680 aSaveNd++; 1681 pDestRedl->GetMark()->nNode = aSaveNd; 1682 pDestRedl->GetMark()->nContent.Assign( aSaveNd.GetNode().GetCntntNode(), 1683 nSaveCnt ); 1684 1685 if( GetPrev() != this ) 1686 { 1687 SwPaM* pTmpPrev = ((_SaveMergeRedlines*)GetPrev())->pDestRedl; 1688 if( pTmpPrev && *pTmpPrev->GetPoint() == *pDestRedl->GetPoint() ) 1689 *pTmpPrev->GetPoint() = *pDestRedl->GetMark(); 1690 } 1691 } 1692 else 1693 { 1694 //JP 21.09.98: Bug 55909 1695 // falls im Doc auf gleicher Pos aber schon ein geloeschter oder 1696 // eingefuegter ist, dann muss dieser gesplittet werden! 1697 SwPosition* pDStt = pDestRedl->GetMark(), 1698 * pDEnd = pDestRedl->GetPoint(); 1699 sal_uInt16 n = 0; 1700 1701 // zur StartPos das erste Redline suchen 1702 if( !pDoc->GetRedline( *pDStt, &n ) && n ) 1703 --n; 1704 1705 const SwRedlineTbl& rRedlineTbl = pDoc->GetRedlineTbl(); 1706 for( ; n < rRedlineTbl.Count(); ++n ) 1707 { 1708 SwRedline* pRedl = rRedlineTbl[ n ]; 1709 SwPosition* pRStt = pRedl->Start(), 1710 * pREnd = pRStt == pRedl->GetPoint() ? pRedl->GetMark() 1711 : pRedl->GetPoint(); 1712 if( nsRedlineType_t::REDLINE_DELETE == pRedl->GetType() || 1713 nsRedlineType_t::REDLINE_INSERT == pRedl->GetType() ) 1714 { 1715 SwComparePosition eCmpPos = ComparePosition( *pDStt, *pDEnd, *pRStt, *pREnd ); 1716 switch( eCmpPos ) 1717 { 1718 case POS_COLLIDE_START: 1719 case POS_BEHIND: 1720 break; 1721 1722 case POS_INSIDE: 1723 case POS_EQUAL: 1724 delete pDestRedl, pDestRedl = 0; 1725 // break; -> kein break !!!! 1726 1727 case POS_COLLIDE_END: 1728 case POS_BEFORE: 1729 n = rRedlineTbl.Count(); 1730 break; 1731 1732 case POS_OUTSIDE: 1733 { 1734 SwRedline* pCpyRedl = new SwRedline( 1735 pDestRedl->GetRedlineData(), *pDStt ); 1736 pCpyRedl->SetMark(); 1737 *pCpyRedl->GetPoint() = *pRStt; 1738 1739 SwUndoCompDoc *const pUndo = 1740 (pDoc->GetIDocumentUndoRedo().DoesUndo()) 1741 ? new SwUndoCompDoc( *pCpyRedl ) : 0; 1742 1743 // now modify doc: append redline, undo (and count) 1744 pDoc->AppendRedline( pCpyRedl, true ); 1745 if( pUndo ) 1746 { 1747 pDoc->GetIDocumentUndoRedo().AppendUndo(pUndo); 1748 } 1749 ++nIns; 1750 1751 *pDStt = *pREnd; 1752 1753 // dann solle man neu anfangen 1754 n = USHRT_MAX; 1755 } 1756 break; 1757 1758 case POS_OVERLAP_BEFORE: 1759 *pDEnd = *pRStt; 1760 break; 1761 1762 case POS_OVERLAP_BEHIND: 1763 *pDStt = *pREnd; 1764 break; 1765 } 1766 } 1767 else if( *pDEnd <= *pRStt ) 1768 break; 1769 } 1770 1771 } 1772 1773 if( pDestRedl ) 1774 { 1775 SwUndoCompDoc *const pUndo = (pDoc->GetIDocumentUndoRedo().DoesUndo()) 1776 ? new SwUndoCompDoc( *pDestRedl ) : 0; 1777 1778 // now modify doc: append redline, undo (and count) 1779 bool bRedlineAccepted = pDoc->AppendRedline( pDestRedl, true ); 1780 if( pUndo ) 1781 { 1782 pDoc->GetIDocumentUndoRedo().AppendUndo( pUndo ); 1783 } 1784 ++nIns; 1785 1786 // if AppendRedline has deleted our redline, we may not keep a 1787 // reference to it 1788 if( ! bRedlineAccepted ) 1789 pDestRedl = NULL; 1790 } 1791 return nIns; 1792 } 1793 1794 // merge zweier Dokumente 1795 long SwDoc::MergeDoc( const SwDoc& rDoc ) 1796 { 1797 if( &rDoc == this ) 1798 return 0; 1799 1800 long nRet = 0; 1801 1802 GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL); 1803 1804 SwDoc& rSrcDoc = (SwDoc&)rDoc; 1805 sal_Bool bSrcModified = rSrcDoc.IsModified(); 1806 1807 RedlineMode_t eSrcRedlMode = rSrcDoc.GetRedlineMode(); 1808 rSrcDoc.SetRedlineMode( nsRedlineMode_t::REDLINE_SHOW_DELETE ); 1809 SetRedlineMode( nsRedlineMode_t::REDLINE_SHOW_DELETE ); 1810 1811 SwCompareData aD0( rSrcDoc ); 1812 SwCompareData aD1( *this ); 1813 1814 aD1.CompareLines( aD0 ); 1815 1816 if( !aD1.HasDiffs( aD0 ) ) 1817 { 1818 // jetzt wollen wir alle Redlines aus dem SourceDoc zu uns bekommen 1819 1820 // suche alle Insert - Redlines aus dem SourceDoc und bestimme 1821 // deren Position im DestDoc 1822 _SaveMergeRedlines* pRing = 0; 1823 const SwRedlineTbl& rSrcRedlTbl = rSrcDoc.GetRedlineTbl(); 1824 sal_uLong nEndOfExtra = rSrcDoc.GetNodes().GetEndOfExtras().GetIndex(); 1825 sal_uLong nMyEndOfExtra = GetNodes().GetEndOfExtras().GetIndex(); 1826 for( sal_uInt16 n = 0; n < rSrcRedlTbl.Count(); ++n ) 1827 { 1828 const SwRedline* pRedl = rSrcRedlTbl[ n ]; 1829 sal_uLong nNd = pRedl->GetPoint()->nNode.GetIndex(); 1830 RedlineType_t eType = pRedl->GetType(); 1831 if( nEndOfExtra < nNd && 1832 ( nsRedlineType_t::REDLINE_INSERT == eType || nsRedlineType_t::REDLINE_DELETE == eType )) 1833 { 1834 const SwNode* pDstNd = GetNodes()[ 1835 nMyEndOfExtra + nNd - nEndOfExtra ]; 1836 1837 // Position gefunden. Dann muss im DestDoc auch 1838 // in der Line das Redline eingefuegt werden 1839 _SaveMergeRedlines* pTmp = new _SaveMergeRedlines( 1840 *pDstNd, *pRedl, pRing ); 1841 if( !pRing ) 1842 pRing = pTmp; 1843 } 1844 } 1845 1846 if( pRing ) 1847 { 1848 // dann alle ins DestDoc ueber nehmen 1849 rSrcDoc.SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE)); 1850 1851 SetRedlineMode((RedlineMode_t)( 1852 nsRedlineMode_t::REDLINE_ON | 1853 nsRedlineMode_t::REDLINE_SHOW_INSERT | 1854 nsRedlineMode_t::REDLINE_SHOW_DELETE)); 1855 1856 _SaveMergeRedlines* pTmp = pRing; 1857 1858 do { 1859 nRet += pTmp->InsertRedline(); 1860 } while( pRing != ( pTmp = (_SaveMergeRedlines*)pTmp->GetNext() )); 1861 1862 while( pRing != pRing->GetNext() ) 1863 delete pRing->GetNext(); 1864 delete pRing; 1865 } 1866 } 1867 1868 rSrcDoc.SetRedlineMode( eSrcRedlMode ); 1869 if( !bSrcModified ) 1870 rSrcDoc.ResetModified(); 1871 1872 SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE)); 1873 1874 GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL); 1875 1876 return nRet; 1877 } 1878 1879 1880