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( 1358 const CompareData& rData, 1359 sal_uLong nStt, 1360 sal_uLong nEnd, 1361 sal_uLong nInsPos ) 1362 { 1363 SwNodeRange aRg( 1364 ((SwCompareLine*)rData.GetLine( nStt ))->GetNode(), 0, 1365 ((SwCompareLine*)rData.GetLine( nEnd-1 ))->GetEndNode(), 1 ); 1366 1367 sal_uInt16 nOffset = 0; 1368 const CompareLine* pLine; 1369 if( GetLineCount() == nInsPos ) 1370 { 1371 pLine = GetLine( nInsPos-1 ); 1372 nOffset = 1; 1373 } 1374 else 1375 pLine = GetLine( nInsPos ); 1376 1377 const SwNode* pLineNd; 1378 if( pLine ) 1379 { 1380 if( nOffset ) 1381 pLineNd = &((SwCompareLine*)pLine)->GetEndNode(); 1382 else 1383 pLineNd = &((SwCompareLine*)pLine)->GetNode(); 1384 } 1385 else 1386 { 1387 pLineNd = &rDoc.GetNodes().GetEndOfContent(); 1388 nOffset = 0; 1389 } 1390 1391 SwNodeIndex aInsPos( *pLineNd, nOffset ); 1392 SwNodeIndex aSavePos( aInsPos, -1 ); 1393 1394 ((SwCompareData&)rData).rDoc.CopyWithFlyInFly( aRg, 0, aInsPos ); 1395 rDoc.SetModified(); 1396 aSavePos++; 1397 1398 // #i65201#: These SwPaMs are calculated when the (old) delete-redlines are hidden, 1399 // they will be inserted when the delete-redlines are shown again. 1400 // To avoid unwanted insertions of delete-redlines into these new redlines, what happens 1401 // especially at the end of the document, I reduce the SwPaM by one node. 1402 // Before the new redlines are inserted, they have to expand again. 1403 SwPaM* pTmp = new SwPaM( aSavePos.GetNode(), aInsPos.GetNode(), 0, -1, pDelRing ); 1404 if( !pDelRing ) 1405 pDelRing = pTmp; 1406 1407 if( pInsRing ) 1408 { 1409 SwPaM* pCorr = (SwPaM*)pInsRing->GetPrev(); 1410 if( *pCorr->GetPoint() == *pTmp->GetPoint() ) 1411 { 1412 SwNodeIndex aTmpPos( pTmp->GetMark()->nNode, -1 ); 1413 *pCorr->GetPoint() = SwPosition( aTmpPos ); 1414 } 1415 } 1416 } 1417 1418 void SwCompareData::CheckForChangesInLine( const CompareData& rData, 1419 sal_uLong& rStt, sal_uLong& rEnd, 1420 sal_uLong& rThisStt, sal_uLong& rThisEnd ) 1421 { 1422 while( rStt < rEnd && rThisStt < rThisEnd ) 1423 { 1424 SwCompareLine* pDstLn = (SwCompareLine*)GetLine( rThisStt ); 1425 SwCompareLine* pSrcLn = (SwCompareLine*)rData.GetLine( rStt ); 1426 if( !pDstLn->ChangesInLine( *pSrcLn, pInsRing, pDelRing ) ) 1427 break; 1428 1429 ++rStt; 1430 ++rThisStt; 1431 } 1432 } 1433 1434 void SwCompareData::SetRedlinesToDoc( sal_Bool bUseDocInfo ) 1435 { 1436 SwPaM* pTmp = pDelRing; 1437 1438 // Bug #83296#: get the Author / TimeStamp from the "other" 1439 // document info 1440 sal_uInt16 nAuthor = rDoc.GetRedlineAuthor(); 1441 DateTime aTimeStamp; 1442 SwDocShell *pDocShell(rDoc.GetDocShell()); 1443 DBG_ASSERT(pDocShell, "no SwDocShell"); 1444 if (pDocShell) { 1445 uno::Reference<document::XDocumentPropertiesSupplier> xDPS( 1446 pDocShell->GetModel(), uno::UNO_QUERY_THROW); 1447 uno::Reference<document::XDocumentProperties> xDocProps( 1448 xDPS->getDocumentProperties()); 1449 DBG_ASSERT(xDocProps.is(), "Doc has no DocumentProperties"); 1450 1451 if( bUseDocInfo && xDocProps.is() ) { 1452 String aTmp( 1 == xDocProps->getEditingCycles() 1453 ? xDocProps->getAuthor() 1454 : xDocProps->getModifiedBy() ); 1455 util::DateTime uDT( 1 == xDocProps->getEditingCycles() 1456 ? xDocProps->getCreationDate() 1457 : xDocProps->getModificationDate() ); 1458 Date d(uDT.Day, uDT.Month, uDT.Year); 1459 Time t(uDT.Hours, uDT.Minutes, uDT.Seconds, uDT.HundredthSeconds); 1460 DateTime aDT(d,t); 1461 1462 if( aTmp.Len() ) 1463 { 1464 nAuthor = rDoc.InsertRedlineAuthor( aTmp ); 1465 aTimeStamp = aDT; 1466 } 1467 } 1468 } 1469 1470 if( pTmp ) 1471 { 1472 SwRedlineData aRedlnData( nsRedlineType_t::REDLINE_DELETE, nAuthor, aTimeStamp, 1473 aEmptyStr, 0, 0 ); 1474 do { 1475 // #i65201#: Expand again, see comment above. 1476 if( pTmp->GetPoint()->nContent == 0 ) 1477 { 1478 pTmp->GetPoint()->nNode++; 1479 pTmp->GetPoint()->nContent.Assign( pTmp->GetCntntNode(), 0 ); 1480 } 1481 // --> mst 2010-05-17 #i101009# 1482 // prevent redlines that end on structural end node 1483 if (& rDoc.GetNodes().GetEndOfContent() == 1484 & pTmp->GetPoint()->nNode.GetNode()) 1485 { 1486 pTmp->GetPoint()->nNode--; 1487 SwCntntNode *const pContentNode( pTmp->GetCntntNode() ); 1488 pTmp->GetPoint()->nContent.Assign( pContentNode, 1489 (pContentNode) ? pContentNode->Len() : 0 ); 1490 } 1491 // <-- 1492 1493 rDoc.DeleteRedline( *pTmp, false, USHRT_MAX ); 1494 1495 if (rDoc.GetIDocumentUndoRedo().DoesUndo()) 1496 { 1497 SwUndo *const pUndo(new SwUndoCompDoc( *pTmp, sal_False )) ; 1498 rDoc.GetIDocumentUndoRedo().AppendUndo(pUndo); 1499 } 1500 rDoc.AppendRedline( new SwRedline( aRedlnData, *pTmp ), true ); 1501 1502 } while( pDelRing != ( pTmp = (SwPaM*)pTmp->GetNext() )); 1503 } 1504 1505 pTmp = pInsRing; 1506 if( pTmp ) 1507 { 1508 do { 1509 if( pTmp->GetPoint()->nContent == 0 ) 1510 { 1511 pTmp->GetPoint()->nNode++; 1512 pTmp->GetPoint()->nContent.Assign( pTmp->GetCntntNode(), 0 ); 1513 } 1514 // --> mst 2010-05-17 #i101009# 1515 // prevent redlines that end on structural end node 1516 if (& rDoc.GetNodes().GetEndOfContent() == 1517 & pTmp->GetPoint()->nNode.GetNode()) 1518 { 1519 pTmp->GetPoint()->nNode--; 1520 SwCntntNode *const pContentNode( pTmp->GetCntntNode() ); 1521 pTmp->GetPoint()->nContent.Assign( pContentNode, 1522 (pContentNode) ? pContentNode->Len() : 0 ); 1523 } 1524 // <-- 1525 } while( pInsRing != ( pTmp = (SwPaM*)pTmp->GetNext() )); 1526 SwRedlineData aRedlnData( nsRedlineType_t::REDLINE_INSERT, nAuthor, aTimeStamp, 1527 aEmptyStr, 0, 0 ); 1528 1529 // zusammenhaengende zusammenfassen 1530 if( pTmp->GetNext() != pInsRing ) 1531 { 1532 const SwCntntNode* pCNd; 1533 do { 1534 SwPosition& rSttEnd = *pTmp->End(), 1535 & rEndStt = *((SwPaM*)pTmp->GetNext())->Start(); 1536 if( rSttEnd == rEndStt || 1537 (!rEndStt.nContent.GetIndex() && 1538 rEndStt.nNode.GetIndex() - 1 == rSttEnd.nNode.GetIndex() && 1539 0 != ( pCNd = rSttEnd.nNode.GetNode().GetCntntNode() ) 1540 ? rSttEnd.nContent.GetIndex() == pCNd->Len() 1541 : 0 )) 1542 { 1543 if( pTmp->GetNext() == pInsRing ) 1544 { 1545 // liegen hintereinander also zusammen fassen 1546 rEndStt = *pTmp->Start(); 1547 delete pTmp; 1548 pTmp = pInsRing; 1549 } 1550 else 1551 { 1552 // liegen hintereinander also zusammen fassen 1553 rSttEnd = *((SwPaM*)pTmp->GetNext())->End(); 1554 delete pTmp->GetNext(); 1555 } 1556 } 1557 else 1558 pTmp = (SwPaM*)pTmp->GetNext(); 1559 } while( pInsRing != pTmp ); 1560 } 1561 1562 do { 1563 if( rDoc.AppendRedline( new SwRedline( aRedlnData, *pTmp ), true) && 1564 rDoc.GetIDocumentUndoRedo().DoesUndo()) 1565 { 1566 SwUndo *const pUndo(new SwUndoCompDoc( *pTmp, sal_True )); 1567 rDoc.GetIDocumentUndoRedo().AppendUndo(pUndo); 1568 } 1569 } while( pInsRing != ( pTmp = (SwPaM*)pTmp->GetNext() )); 1570 } 1571 } 1572 1573 /* */ 1574 1575 1576 1577 // returnt (?die Anzahl der Unterschiede?) ob etwas unterschiedlich ist 1578 long SwDoc::CompareDoc( const SwDoc& rDoc ) 1579 { 1580 if( &rDoc == this ) 1581 return 0; 1582 1583 long nRet = 0; 1584 1585 GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL); 1586 sal_Bool bDocWasModified = IsModified(); 1587 SwDoc& rSrcDoc = (SwDoc&)rDoc; 1588 sal_Bool bSrcModified = rSrcDoc.IsModified(); 1589 1590 RedlineMode_t eSrcRedlMode = rSrcDoc.GetRedlineMode(); 1591 rSrcDoc.SetRedlineMode( nsRedlineMode_t::REDLINE_SHOW_INSERT ); 1592 SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT)); 1593 1594 SwCompareData aD0( rSrcDoc ); 1595 SwCompareData aD1( *this ); 1596 1597 aD1.CompareLines( aD0 ); 1598 1599 nRet = aD1.ShowDiffs( aD0 ); 1600 1601 if( nRet ) 1602 { 1603 SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | 1604 nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE)); 1605 1606 aD1.SetRedlinesToDoc( !bDocWasModified ); 1607 SetModified(); 1608 } 1609 1610 rSrcDoc.SetRedlineMode( eSrcRedlMode ); 1611 SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE)); 1612 1613 if( !bSrcModified ) 1614 rSrcDoc.ResetModified(); 1615 1616 GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL); 1617 1618 return nRet; 1619 } 1620 1621 1622 class _SaveMergeRedlines : public Ring 1623 { 1624 const SwRedline* pSrcRedl; 1625 SwRedline* pDestRedl; 1626 public: 1627 _SaveMergeRedlines( const SwNode& rDstNd, 1628 const SwRedline& rSrcRedl, Ring* pRing ); 1629 sal_uInt16 InsertRedline(); 1630 1631 SwRedline* GetDestRedline() { return pDestRedl; } 1632 }; 1633 1634 _SaveMergeRedlines::_SaveMergeRedlines( const SwNode& rDstNd, 1635 const SwRedline& rSrcRedl, Ring* pRing ) 1636 : Ring( pRing ), pSrcRedl( &rSrcRedl ) 1637 { 1638 SwPosition aPos( rDstNd ); 1639 1640 const SwPosition* pStt = rSrcRedl.Start(); 1641 if( rDstNd.IsCntntNode() ) 1642 aPos.nContent.Assign( ((SwCntntNode*)&rDstNd), pStt->nContent.GetIndex() ); 1643 pDestRedl = new SwRedline( rSrcRedl.GetRedlineData(), aPos ); 1644 1645 if( nsRedlineType_t::REDLINE_DELETE == pDestRedl->GetType() ) 1646 { 1647 // den Bereich als geloescht kennzeichnen 1648 const SwPosition* pEnd = pStt == rSrcRedl.GetPoint() 1649 ? rSrcRedl.GetMark() 1650 : rSrcRedl.GetPoint(); 1651 1652 pDestRedl->SetMark(); 1653 pDestRedl->GetPoint()->nNode += pEnd->nNode.GetIndex() - 1654 pStt->nNode.GetIndex(); 1655 pDestRedl->GetPoint()->nContent.Assign( pDestRedl->GetCntntNode(), 1656 pEnd->nContent.GetIndex() ); 1657 } 1658 } 1659 1660 sal_uInt16 _SaveMergeRedlines::InsertRedline() 1661 { 1662 sal_uInt16 nIns = 0; 1663 SwDoc* pDoc = pDestRedl->GetDoc(); 1664 1665 if( nsRedlineType_t::REDLINE_INSERT == pDestRedl->GetType() ) 1666 { 1667 // der Teil wurde eingefuegt, also kopiere ihn aus dem SourceDoc 1668 ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); 1669 1670 SwNodeIndex aSaveNd( pDestRedl->GetPoint()->nNode, -1 ); 1671 xub_StrLen nSaveCnt = pDestRedl->GetPoint()->nContent.GetIndex(); 1672 1673 RedlineMode_t eOld = pDoc->GetRedlineMode(); 1674 pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE)); 1675 1676 pSrcRedl->GetDoc()->CopyRange( 1677 *const_cast<SwPaM*>(static_cast<const SwPaM*>(pSrcRedl)), 1678 *pDestRedl->GetPoint(), false ); 1679 1680 pDoc->SetRedlineMode_intern( eOld ); 1681 1682 pDestRedl->SetMark(); 1683 aSaveNd++; 1684 pDestRedl->GetMark()->nNode = aSaveNd; 1685 pDestRedl->GetMark()->nContent.Assign( aSaveNd.GetNode().GetCntntNode(), 1686 nSaveCnt ); 1687 1688 if( GetPrev() != this ) 1689 { 1690 SwPaM* pTmpPrev = ((_SaveMergeRedlines*)GetPrev())->pDestRedl; 1691 if( pTmpPrev && *pTmpPrev->GetPoint() == *pDestRedl->GetPoint() ) 1692 *pTmpPrev->GetPoint() = *pDestRedl->GetMark(); 1693 } 1694 } 1695 else 1696 { 1697 //JP 21.09.98: Bug 55909 1698 // falls im Doc auf gleicher Pos aber schon ein geloeschter oder 1699 // eingefuegter ist, dann muss dieser gesplittet werden! 1700 SwPosition* pDStt = pDestRedl->GetMark(), 1701 * pDEnd = pDestRedl->GetPoint(); 1702 sal_uInt16 n = 0; 1703 1704 // zur StartPos das erste Redline suchen 1705 if( !pDoc->GetRedline( *pDStt, &n ) && n ) 1706 --n; 1707 1708 const SwRedlineTbl& rRedlineTbl = pDoc->GetRedlineTbl(); 1709 for( ; n < rRedlineTbl.Count(); ++n ) 1710 { 1711 SwRedline* pRedl = rRedlineTbl[ n ]; 1712 SwPosition* pRStt = pRedl->Start(), 1713 * pREnd = pRStt == pRedl->GetPoint() ? pRedl->GetMark() 1714 : pRedl->GetPoint(); 1715 if( nsRedlineType_t::REDLINE_DELETE == pRedl->GetType() || 1716 nsRedlineType_t::REDLINE_INSERT == pRedl->GetType() ) 1717 { 1718 SwComparePosition eCmpPos = ComparePosition( *pDStt, *pDEnd, *pRStt, *pREnd ); 1719 switch( eCmpPos ) 1720 { 1721 case POS_COLLIDE_START: 1722 case POS_BEHIND: 1723 break; 1724 1725 case POS_INSIDE: 1726 case POS_EQUAL: 1727 delete pDestRedl, pDestRedl = 0; 1728 // break; -> kein break !!!! 1729 1730 case POS_COLLIDE_END: 1731 case POS_BEFORE: 1732 n = rRedlineTbl.Count(); 1733 break; 1734 1735 case POS_OUTSIDE: 1736 { 1737 SwRedline* pCpyRedl = new SwRedline( 1738 pDestRedl->GetRedlineData(), *pDStt ); 1739 pCpyRedl->SetMark(); 1740 *pCpyRedl->GetPoint() = *pRStt; 1741 1742 SwUndoCompDoc *const pUndo = 1743 (pDoc->GetIDocumentUndoRedo().DoesUndo()) 1744 ? new SwUndoCompDoc( *pCpyRedl ) : 0; 1745 1746 // now modify doc: append redline, undo (and count) 1747 pDoc->AppendRedline( pCpyRedl, true ); 1748 if( pUndo ) 1749 { 1750 pDoc->GetIDocumentUndoRedo().AppendUndo(pUndo); 1751 } 1752 ++nIns; 1753 1754 *pDStt = *pREnd; 1755 1756 // dann solle man neu anfangen 1757 n = USHRT_MAX; 1758 } 1759 break; 1760 1761 case POS_OVERLAP_BEFORE: 1762 *pDEnd = *pRStt; 1763 break; 1764 1765 case POS_OVERLAP_BEHIND: 1766 *pDStt = *pREnd; 1767 break; 1768 } 1769 } 1770 else if( *pDEnd <= *pRStt ) 1771 break; 1772 } 1773 1774 } 1775 1776 if( pDestRedl ) 1777 { 1778 SwUndoCompDoc *const pUndo = (pDoc->GetIDocumentUndoRedo().DoesUndo()) 1779 ? new SwUndoCompDoc( *pDestRedl ) : 0; 1780 1781 // now modify doc: append redline, undo (and count) 1782 bool bRedlineAccepted = pDoc->AppendRedline( pDestRedl, true ); 1783 if( pUndo ) 1784 { 1785 pDoc->GetIDocumentUndoRedo().AppendUndo( pUndo ); 1786 } 1787 ++nIns; 1788 1789 // if AppendRedline has deleted our redline, we may not keep a 1790 // reference to it 1791 if( ! bRedlineAccepted ) 1792 pDestRedl = NULL; 1793 } 1794 return nIns; 1795 } 1796 1797 // merge zweier Dokumente 1798 long SwDoc::MergeDoc( const SwDoc& rDoc ) 1799 { 1800 if( &rDoc == this ) 1801 return 0; 1802 1803 long nRet = 0; 1804 1805 GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL); 1806 1807 SwDoc& rSrcDoc = (SwDoc&)rDoc; 1808 sal_Bool bSrcModified = rSrcDoc.IsModified(); 1809 1810 RedlineMode_t eSrcRedlMode = rSrcDoc.GetRedlineMode(); 1811 rSrcDoc.SetRedlineMode( nsRedlineMode_t::REDLINE_SHOW_DELETE ); 1812 SetRedlineMode( nsRedlineMode_t::REDLINE_SHOW_DELETE ); 1813 1814 SwCompareData aD0( rSrcDoc ); 1815 SwCompareData aD1( *this ); 1816 1817 aD1.CompareLines( aD0 ); 1818 1819 if( !aD1.HasDiffs( aD0 ) ) 1820 { 1821 // jetzt wollen wir alle Redlines aus dem SourceDoc zu uns bekommen 1822 1823 // suche alle Insert - Redlines aus dem SourceDoc und bestimme 1824 // deren Position im DestDoc 1825 _SaveMergeRedlines* pRing = 0; 1826 const SwRedlineTbl& rSrcRedlTbl = rSrcDoc.GetRedlineTbl(); 1827 sal_uLong nEndOfExtra = rSrcDoc.GetNodes().GetEndOfExtras().GetIndex(); 1828 sal_uLong nMyEndOfExtra = GetNodes().GetEndOfExtras().GetIndex(); 1829 for( sal_uInt16 n = 0; n < rSrcRedlTbl.Count(); ++n ) 1830 { 1831 const SwRedline* pRedl = rSrcRedlTbl[ n ]; 1832 sal_uLong nNd = pRedl->GetPoint()->nNode.GetIndex(); 1833 RedlineType_t eType = pRedl->GetType(); 1834 if( nEndOfExtra < nNd && 1835 ( nsRedlineType_t::REDLINE_INSERT == eType || nsRedlineType_t::REDLINE_DELETE == eType )) 1836 { 1837 const SwNode* pDstNd = GetNodes()[ 1838 nMyEndOfExtra + nNd - nEndOfExtra ]; 1839 1840 // Position gefunden. Dann muss im DestDoc auch 1841 // in der Line das Redline eingefuegt werden 1842 _SaveMergeRedlines* pTmp = new _SaveMergeRedlines( 1843 *pDstNd, *pRedl, pRing ); 1844 if( !pRing ) 1845 pRing = pTmp; 1846 } 1847 } 1848 1849 if( pRing ) 1850 { 1851 // dann alle ins DestDoc ueber nehmen 1852 rSrcDoc.SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE)); 1853 1854 SetRedlineMode((RedlineMode_t)( 1855 nsRedlineMode_t::REDLINE_ON | 1856 nsRedlineMode_t::REDLINE_SHOW_INSERT | 1857 nsRedlineMode_t::REDLINE_SHOW_DELETE)); 1858 1859 _SaveMergeRedlines* pTmp = pRing; 1860 1861 do { 1862 nRet += pTmp->InsertRedline(); 1863 } while( pRing != ( pTmp = (_SaveMergeRedlines*)pTmp->GetNext() )); 1864 1865 while( pRing != pRing->GetNext() ) 1866 delete pRing->GetNext(); 1867 delete pRing; 1868 } 1869 } 1870 1871 rSrcDoc.SetRedlineMode( eSrcRedlMode ); 1872 if( !bSrcModified ) 1873 rSrcDoc.ResetModified(); 1874 1875 SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE)); 1876 1877 GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL); 1878 1879 return nRet; 1880 } 1881 1882 1883