1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: doccomp.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <hintids.hxx>
36 #include <tools/list.hxx>
37 #include <vcl/vclenum.hxx>
38 #include <svx/crsditem.hxx>
39 #include <svx/colritem.hxx>
40 #include <svx/boxitem.hxx>
41 #include <svx/udlnitem.hxx>
46 #include <redline.hxx>
48 #include <section.hxx>
52 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
53 #include <com/sun/star/document/XDocumentProperties.hpp>
55 using namespace ::com::sun::star
;
62 virtual ~CompareLine();
64 virtual ULONG
GetHashValue() const = 0;
65 virtual BOOL
Compare( const CompareLine
& rLine
) const = 0;
68 DECLARE_LIST( CompareList
, CompareLine
* )
79 // Anfang und Ende beschneiden und alle anderen in das
81 virtual void CheckRanges( CompareData
& ) = 0;
85 virtual ~CompareData();
87 // gibt es unterschiede?
88 BOOL
HasDiffs( const CompareData
& rData
) const;
90 // startet das Vergleichen und Erzeugen der Unterschiede zweier
92 void CompareLines( CompareData
& rData
);
93 // lasse die Unterschiede anzeigen - ruft die beiden Methoden
94 // ShowInsert / ShowDelete. Diese bekommen die Start und EndLine-Nummer
95 // uebergeben. Die Abbildung auf den tatsaechline Inhalt muss die
96 // Ableitung uebernehmen!
97 ULONG
ShowDiffs( const CompareData
& rData
);
99 virtual void ShowInsert( ULONG nStt
, ULONG nEnd
);
100 virtual void ShowDelete( const CompareData
& rData
, ULONG nStt
,
101 ULONG nEnd
, ULONG nInsPos
);
102 virtual void CheckForChangesInLine( const CompareData
& rData
,
103 ULONG
& nStt
, ULONG
& nEnd
,
104 ULONG
& nThisStt
, ULONG
& nThisEnd
);
106 // Eindeutigen Index fuer eine Line setzen. Gleiche Lines haben den
107 // selben Index; auch in den anderen CompareData!
108 void SetIndex( ULONG nLine
, ULONG nIndex
);
109 ULONG
GetIndex( ULONG nLine
) const
110 { return nLine
< aLines
.Count() ? pIndex
[ nLine
] : 0; }
112 // setze/erfrage ob eine Zeile veraendert ist
113 void SetChanged( ULONG nLine
, BOOL bFlag
= TRUE
);
114 BOOL
GetChanged( ULONG nLine
) const
116 return (pChangedFlag
&& nLine
< aLines
.Count())
117 ? pChangedFlag
[ nLine
]
121 ULONG
GetLineCount() const { return aLines
.Count(); }
122 ULONG
GetLineOffset() const { return nSttLineNum
; }
123 const CompareLine
* GetLine( ULONG nLine
) const
124 { return aLines
.GetObject( nLine
); }
125 void InsertLine( CompareLine
* pLine
)
126 { aLines
.Insert( pLine
, LIST_APPEND
); }
134 const CompareLine
* pLine
;
137 : nNext( 0 ), nHash( 0 ), pLine(0) {}
142 ULONG nCount
, nPrime
;
148 void CalcHashValue( CompareData
& rData
);
150 ULONG
GetCount() const { return nCount
; }
163 MovedData( CompareData
& rData
, sal_Char
* pDiscard
);
166 ULONG
GetIndex( ULONG n
) const { return pIndex
[ n
]; }
167 ULONG
GetLineNum( ULONG n
) const { return pLineNum
[ n
]; }
168 ULONG
GetCount() const { return nCount
; }
172 // Suche die verschobenen Lines
173 class CompareSequence
175 CompareData
&rData1
, &rData2
;
176 const MovedData
&rMoved1
, &rMoved2
;
177 long *pMemory
, *pFDiag
, *pBDiag
;
179 void Compare( ULONG nStt1
, ULONG nEnd1
, ULONG nStt2
, ULONG nEnd2
);
180 ULONG
CheckDiag( ULONG nStt1
, ULONG nEnd1
,
181 ULONG nStt2
, ULONG nEnd2
, ULONG
* pCost
);
183 CompareSequence( CompareData
& rData1
, CompareData
& rData2
,
184 const MovedData
& rD1
, const MovedData
& rD2
);
189 static void CountDifference( const CompareData
& rData
, ULONG
* pCounts
);
190 static void SetDiscard( const CompareData
& rData
,
191 sal_Char
* pDiscard
, ULONG
* pCounts
);
192 static void CheckDiscard( ULONG nLen
, sal_Char
* pDiscard
);
193 static ULONG
SetChangedFlag( CompareData
& rData
, sal_Char
* pDiscard
, int bFirst
);
194 static void ShiftBoundaries( CompareData
& rData1
, CompareData
& rData2
);
197 Compare( ULONG nDiff
, CompareData
& rData1
, CompareData
& rData2
);
200 // ====================================================================
202 CompareLine::~CompareLine() {}
204 // ----------------------------------------------------------------------
206 CompareData::CompareData()
207 : pIndex( 0 ), pChangedFlag( 0 ), nSttLineNum( 0 )
211 CompareData::~CompareData()
214 delete[] pChangedFlag
;
217 void CompareData::SetIndex( ULONG nLine
, ULONG nIndex
)
221 pIndex
= new ULONG
[ aLines
.Count() ];
222 memset( pIndex
, 0, aLines
.Count() * sizeof( ULONG
) );
224 if( nLine
< aLines
.Count() )
225 pIndex
[ nLine
] = nIndex
;
228 void CompareData::SetChanged( ULONG nLine
, BOOL bFlag
)
232 pChangedFlag
= new BOOL
[ aLines
.Count() +1 ];
233 memset( pChangedFlag
, 0, aLines
.Count() +1 * sizeof( BOOL
) );
235 if( nLine
< aLines
.Count() )
236 pChangedFlag
[ nLine
] = bFlag
;
239 void CompareData::CompareLines( CompareData
& rData
)
241 CheckRanges( rData
);
245 Hash
aH( GetLineCount() + rData
.GetLineCount() + 1 );
246 aH
.CalcHashValue( *this );
247 aH
.CalcHashValue( rData
);
248 nDifferent
= aH
.GetCount();
251 Compare
aComp( nDifferent
, *this, rData
);
255 ULONG
CompareData::ShowDiffs( const CompareData
& rData
)
257 ULONG nLen1
= rData
.GetLineCount(), nLen2
= GetLineCount();
258 ULONG nStt1
= 0, nStt2
= 0;
261 while( nStt1
< nLen1
|| nStt2
< nLen2
)
263 if( rData
.GetChanged( nStt1
) || GetChanged( nStt2
) )
265 ULONG nSav1
= nStt1
, nSav2
= nStt2
;
266 while( nStt1
< nLen1
&& rData
.GetChanged( nStt1
)) ++nStt1
;
267 while( nStt2
< nLen2
&& GetChanged( nStt2
)) ++nStt2
;
269 // rData ist das Original,
270 // this ist das, in das die Veraenderungen sollen
271 if( nSav2
!= nStt2
&& nSav1
!= nStt1
)
272 CheckForChangesInLine( rData
, nSav1
, nStt1
, nSav2
, nStt2
);
275 ShowInsert( nSav2
, nStt2
);
278 ShowDelete( rData
, nSav1
, nStt1
, nStt2
);
286 BOOL
CompareData::HasDiffs( const CompareData
& rData
) const
289 ULONG nLen1
= rData
.GetLineCount(), nLen2
= GetLineCount();
290 ULONG nStt1
= 0, nStt2
= 0;
292 while( nStt1
< nLen1
|| nStt2
< nLen2
)
294 if( rData
.GetChanged( nStt1
) || GetChanged( nStt2
) )
304 void CompareData::ShowInsert( ULONG
, ULONG
)
308 void CompareData::ShowDelete( const CompareData
&, ULONG
, ULONG
, ULONG
)
312 void CompareData::CheckForChangesInLine( const CompareData
& ,
313 ULONG
&, ULONG
&, ULONG
&, ULONG
& )
317 // ----------------------------------------------------------------------
319 Hash::Hash( ULONG nSize
)
323 static const ULONG primes
[] =
342 67108859, /* Preposterously large . . . */
352 pDataArr
= new _HashData
[ nSize
];
353 pDataArr
[0].nNext
= 0;
354 pDataArr
[0].nHash
= 0,
355 pDataArr
[0].pLine
= 0;
357 for( i
= 0; primes
[i
] < nSize
/ 3; i
++)
363 nPrime
= primes
[ i
];
364 pHashArr
= new ULONG
[ nPrime
];
365 memset( pHashArr
, 0, nPrime
* sizeof( ULONG
) );
374 void Hash::CalcHashValue( CompareData
& rData
)
378 for( ULONG n
= 0; n
< rData
.GetLineCount(); ++n
)
380 const CompareLine
* pLine
= rData
.GetLine( n
);
381 ASSERT( pLine
, "wo ist die Line?" );
382 ULONG nH
= pLine
->GetHashValue();
384 ULONG
* pFound
= &pHashArr
[ nH
% nPrime
];
386 for( i
= *pFound
; ; i
= pDataArr
[i
].nNext
)
390 pDataArr
[i
].nNext
= *pFound
;
391 pDataArr
[i
].nHash
= nH
;
392 pDataArr
[i
].pLine
= pLine
;
396 else if( pDataArr
[i
].nHash
== nH
&&
397 pDataArr
[i
].pLine
->Compare( *pLine
))
400 rData
.SetIndex( n
, i
);
405 // ----------------------------------------------------------------------
407 Compare::Compare( ULONG nDiff
, CompareData
& rData1
, CompareData
& rData2
)
409 MovedData
*pMD1
, *pMD2
;
410 // Suche die unterschiedlichen Lines
412 sal_Char
* pDiscard1
= new sal_Char
[ rData1
.GetLineCount() ];
413 sal_Char
* pDiscard2
= new sal_Char
[ rData2
.GetLineCount() ];
415 ULONG
* pCount1
= new ULONG
[ nDiff
];
416 ULONG
* pCount2
= new ULONG
[ nDiff
];
417 memset( pCount1
, 0, nDiff
* sizeof( ULONG
));
418 memset( pCount2
, 0, nDiff
* sizeof( ULONG
));
420 // stelle fest, welche Indizies in den CompareData mehrfach vergeben wurden
421 CountDifference( rData1
, pCount1
);
422 CountDifference( rData2
, pCount2
);
424 // alle die jetzt nur einmal vorhanden sind, sind eingefuegt oder
425 // geloescht worden. Alle die im anderen auch vorhanden sind, sind
427 SetDiscard( rData1
, pDiscard1
, pCount2
);
428 SetDiscard( rData2
, pDiscard2
, pCount1
);
430 // die Arrays koennen wir wieder vergessen
431 delete pCount1
; delete pCount2
;
433 CheckDiscard( rData1
.GetLineCount(), pDiscard1
);
434 CheckDiscard( rData2
.GetLineCount(), pDiscard2
);
436 pMD1
= new MovedData( rData1
, pDiscard1
);
437 pMD2
= new MovedData( rData2
, pDiscard2
);
439 // die Arrays koennen wir wieder vergessen
440 delete pDiscard1
; delete pDiscard2
;
444 CompareSequence
aTmp( rData1
, rData2
, *pMD1
, *pMD2
);
447 ShiftBoundaries( rData1
, rData2
);
455 void Compare::CountDifference( const CompareData
& rData
, ULONG
* pCounts
)
457 ULONG nLen
= rData
.GetLineCount();
458 for( ULONG n
= 0; n
< nLen
; ++n
)
460 ULONG nIdx
= rData
.GetIndex( n
);
465 void Compare::SetDiscard( const CompareData
& rData
,
466 sal_Char
* pDiscard
, ULONG
* pCounts
)
468 ULONG nLen
= rData
.GetLineCount();
470 // berechne Max in Abhanegigkeit zur LineAnzahl
474 for( n
= nLen
/ 64; ( n
= n
>> 2 ) > 0; )
477 for( n
= 0; n
< nLen
; ++n
)
479 ULONG nIdx
= rData
.GetIndex( n
);
482 nIdx
= pCounts
[ nIdx
];
483 pDiscard
[ n
] = !nIdx
? 1 : nIdx
> nMax
? 2 : 0;
490 void Compare::CheckDiscard( ULONG nLen
, sal_Char
* pDiscard
)
492 for( ULONG n
= 0; n
< nLen
; ++n
)
494 if( 2 == pDiscard
[ n
] )
496 else if( pDiscard
[ n
] )
500 ULONG provisional
= 0;
502 /* Find end of this run of discardable lines.
503 Count how many are provisionally discardable. */
504 for (j
= n
; j
< nLen
; j
++)
508 if( 2 == pDiscard
[j
] )
512 /* Cancel provisional discards at end, and shrink the run. */
513 while( j
> n
&& 2 == pDiscard
[j
- 1] )
514 pDiscard
[ --j
] = 0, --provisional
;
516 /* Now we have the length of a run of discardable lines
517 whose first and last are not provisional. */
520 /* If 1/4 of the lines in the run are provisional,
521 cancel discarding of all provisional lines in the run. */
522 if (provisional
* 4 > length
)
525 if (pDiscard
[--j
] == 2)
532 ULONG tem
= length
/ 4;
534 /* MINIMUM is approximate square root of LENGTH/4.
535 A subrun of two or more provisionals can stand
536 when LENGTH is at least 16.
537 A subrun of 4 or more can stand when LENGTH >= 64. */
538 while ((tem
= tem
>> 2) > 0)
542 /* Cancel any subrun of MINIMUM or more provisionals
543 within the larger run. */
544 for (j
= 0, consec
= 0; j
< length
; j
++)
545 if (pDiscard
[n
+ j
] != 2)
547 else if (minimum
== ++consec
)
548 /* Back up to start of subrun, to cancel it all. */
550 else if (minimum
< consec
)
553 /* Scan from beginning of run
554 until we find 3 or more nonprovisionals in a row
555 or until the first nonprovisional at least 8 lines in.
556 Until that point, cancel any provisionals. */
557 for (j
= 0, consec
= 0; j
< length
; j
++)
559 if (j
>= 8 && pDiscard
[n
+ j
] == 1)
561 if (pDiscard
[n
+ j
] == 2)
562 consec
= 0, pDiscard
[n
+ j
] = 0;
563 else if (pDiscard
[n
+ j
] == 0)
571 /* I advances to the last line of the run. */
574 /* Same thing, from end. */
575 for (j
= 0, consec
= 0; j
< length
; j
++)
577 if (j
>= 8 && pDiscard
[n
- j
] == 1)
579 if (pDiscard
[n
- j
] == 2)
580 consec
= 0, pDiscard
[n
- j
] = 0;
581 else if (pDiscard
[n
- j
] == 0)
593 // ----------------------------------------------------------------------
595 Compare::MovedData::MovedData( CompareData
& rData
, sal_Char
* pDiscard
)
596 : pIndex( 0 ), pLineNum( 0 ), nCount( 0 )
598 ULONG nLen
= rData
.GetLineCount();
601 for( n
= 0; n
< nLen
; ++n
)
603 rData
.SetChanged( n
);
609 pIndex
= new ULONG
[ nCount
];
610 pLineNum
= new ULONG
[ nCount
];
612 for( n
= 0, nCount
= 0; n
< nLen
; ++n
)
615 pIndex
[ nCount
] = rData
.GetIndex( n
);
616 pLineNum
[ nCount
++ ] = n
;
621 Compare::MovedData::~MovedData()
627 // ----------------------------------------------------------------------
629 // Suche die verschobenen Lines
630 Compare::CompareSequence::CompareSequence(
631 CompareData
& rD1
, CompareData
& rD2
,
632 const MovedData
& rMD1
, const MovedData
& rMD2
)
633 : rData1( rD1
), rData2( rD2
), rMoved1( rMD1
), rMoved2( rMD2
)
635 ULONG nSize
= rMD1
.GetCount() + rMD2
.GetCount() + 3;
636 pMemory
= new long[ nSize
* 2 ];
637 pFDiag
= pMemory
+ ( rMD2
.GetCount() + 1 );
638 pBDiag
= pMemory
+ ( nSize
+ rMD2
.GetCount() + 1 );
640 Compare( 0, rMD1
.GetCount(), 0, rMD2
.GetCount() );
643 Compare::CompareSequence::~CompareSequence()
648 void Compare::CompareSequence::Compare( ULONG nStt1
, ULONG nEnd1
,
649 ULONG nStt2
, ULONG nEnd2
)
651 /* Slide down the bottom initial diagonal. */
652 while( nStt1
< nEnd1
&& nStt2
< nEnd2
&&
653 rMoved1
.GetIndex( nStt1
) == rMoved2
.GetIndex( nStt2
))
656 /* Slide up the top initial diagonal. */
657 while( nEnd1
> nStt1
&& nEnd2
> nStt2
&&
658 rMoved1
.GetIndex( nEnd1
- 1 ) == rMoved2
.GetIndex( nEnd2
- 1 ))
661 /* Handle simple cases. */
663 while( nStt2
< nEnd2
)
664 rData2
.SetChanged( rMoved2
.GetLineNum( nStt2
++ ));
666 else if (nStt2
== nEnd2
)
667 while (nStt1
< nEnd1
)
668 rData1
.SetChanged( rMoved1
.GetLineNum( nStt1
++ ));
674 /* Find a point of correspondence in the middle of the files. */
676 d
= CheckDiag( nStt1
, nEnd1
, nStt2
, nEnd2
, &c
);
681 /* Use that point to split this problem into two subproblems. */
682 Compare( nStt1
, b
, nStt2
, b
- d
);
683 /* This used to use f instead of b,
684 but that is incorrect!
685 It is not necessarily the case that diagonal d
686 has a snake from b to f. */
687 Compare( b
, nEnd1
, b
- d
, nEnd2
);
692 ULONG
Compare::CompareSequence::CheckDiag( ULONG nStt1
, ULONG nEnd1
,
693 ULONG nStt2
, ULONG nEnd2
, ULONG
* pCost
)
695 const long dmin
= nStt1
- nEnd2
; /* Minimum valid diagonal. */
696 const long dmax
= nEnd1
- nStt2
; /* Maximum valid diagonal. */
697 const long fmid
= nStt1
- nStt2
; /* Center diagonal of top-down search. */
698 const long bmid
= nEnd1
- nEnd2
; /* Center diagonal of bottom-up search. */
700 long fmin
= fmid
, fmax
= fmid
; /* Limits of top-down search. */
701 long bmin
= bmid
, bmax
= bmid
; /* Limits of bottom-up search. */
704 long odd
= (fmid
- bmid
) & 1; /* True if southeast corner is on an odd
705 diagonal with respect to the northwest. */
707 pFDiag
[fmid
] = nStt1
;
708 pBDiag
[bmid
] = nEnd1
;
712 long d
; /* Active diagonal. */
715 /* Extend the top-down search by an edit step in each diagonal. */
716 fmin
> dmin
? pFDiag
[--fmin
- 1] = -1 : ++fmin
;
717 fmax
< dmax
? pFDiag
[++fmax
+ 1] = -1 : --fmax
;
718 for (d
= fmax
; d
>= fmin
; d
-= 2)
720 long x
, y
, oldx
, tlo
= pFDiag
[d
- 1], thi
= pFDiag
[d
+ 1];
728 while( ULONG(x
) < nEnd1
&& ULONG(y
) < nEnd2
&&
729 rMoved1
.GetIndex( x
) == rMoved2
.GetIndex( y
))
734 if( odd
&& bmin
<= d
&& d
<= bmax
&& pBDiag
[d
] <= pFDiag
[d
] )
741 /* Similar extend the bottom-up search. */
742 bmin
> dmin
? pBDiag
[--bmin
- 1] = INT_MAX
: ++bmin
;
743 bmax
< dmax
? pBDiag
[++bmax
+ 1] = INT_MAX
: --bmax
;
744 for (d
= bmax
; d
>= bmin
; d
-= 2)
746 long x
, y
, oldx
, tlo
= pBDiag
[d
- 1], thi
= pBDiag
[d
+ 1];
754 while( ULONG(x
) > nStt1
&& ULONG(y
) > nStt2
&&
755 rMoved1
.GetIndex( x
- 1 ) == rMoved2
.GetIndex( y
- 1 ))
760 if (!odd
&& fmin
<= d
&& d
<= fmax
&& pBDiag
[d
] <= pFDiag
[d
])
769 void Compare::ShiftBoundaries( CompareData
& rData1
, CompareData
& rData2
)
771 for( int iz
= 0; iz
< 2; ++iz
)
773 CompareData
* pData
= &rData1
;
774 CompareData
* pOtherData
= &rData2
;
778 ULONG i_end
= pData
->GetLineCount();
779 ULONG preceding
= ULONG_MAX
;
780 ULONG other_preceding
= ULONG_MAX
;
784 ULONG start
, other_start
;
786 /* Scan forwards to find beginning of another run of changes.
787 Also keep track of the corresponding point in the other file. */
789 while( i
< i_end
&& !pData
->GetChanged( i
) )
791 while( pOtherData
->GetChanged( j
++ ))
792 /* Non-corresponding lines in the other file
793 will count as the preceding batch of changes. */
806 /* Now find the end of this run of changes. */
808 while( pData
->GetChanged( ++i
))
811 /* If the first changed line matches the following unchanged one,
812 and this run does not follow right after a previous run,
813 and there are no lines deleted from the other file here,
814 then classify the first changed line as unchanged
815 and the following line as changed in its place. */
817 /* You might ask, how could this run follow right after another?
818 Only because the previous run was shifted here. */
821 pData
->GetIndex( start
) == pData
->GetIndex( i
) &&
822 !pOtherData
->GetChanged( j
) &&
823 !( start
== preceding
|| other_start
== other_preceding
))
825 pData
->SetChanged( start
++, 0 );
826 pData
->SetChanged( i
);
827 /* Since one line-that-matches is now before this run
828 instead of after, we must advance in the other file
841 pOtherData
= &rData1
;
847 class SwCompareLine
: public CompareLine
851 SwCompareLine( const SwNode
& rNd
);
852 virtual ~SwCompareLine();
854 virtual ULONG
GetHashValue() const;
855 virtual BOOL
Compare( const CompareLine
& rLine
) const;
857 static ULONG
GetTxtNodeHashValue( const SwTxtNode
& rNd
, ULONG nVal
);
858 static BOOL
CompareNode( const SwNode
& rDstNd
, const SwNode
& rSrcNd
);
859 static BOOL
CompareTxtNd( const SwTxtNode
& rDstNd
,
860 const SwTxtNode
& rSrcNd
);
862 BOOL
ChangesInLine( const SwCompareLine
& rLine
,
863 SwPaM
*& rpInsRing
, SwPaM
*& rpDelRing
) const;
865 const SwNode
& GetNode() const { return rNode
; }
867 const SwNode
& GetEndNode() const;
870 String
GetText() const;
873 class SwCompareData
: public CompareData
876 SwPaM
*pInsRing
, *pDelRing
;
878 ULONG
PrevIdx( const SwNode
* pNd
);
879 ULONG
NextIdx( const SwNode
* pNd
);
881 virtual void CheckRanges( CompareData
& );
882 virtual void ShowInsert( ULONG nStt
, ULONG nEnd
);
883 virtual void ShowDelete( const CompareData
& rData
, ULONG nStt
,
884 ULONG nEnd
, ULONG nInsPos
);
886 virtual void CheckForChangesInLine( const CompareData
& rData
,
887 ULONG
& nStt
, ULONG
& nEnd
,
888 ULONG
& nThisStt
, ULONG
& nThisEnd
);
891 SwCompareData( SwDoc
& rD
) : rDoc( rD
), pInsRing(0), pDelRing(0) {}
892 virtual ~SwCompareData();
894 void SetRedlinesToDoc( BOOL bUseDocInfo
);
897 // ----------------------------------------------------------------
899 SwCompareLine::SwCompareLine( const SwNode
& rNd
)
904 SwCompareLine::~SwCompareLine()
908 ULONG
SwCompareLine::GetHashValue() const
911 switch( rNode
.GetNodeType() )
914 nRet
= GetTxtNodeHashValue( (SwTxtNode
&)rNode
, nRet
);
919 const SwNode
* pEndNd
= rNode
.EndOfSectionNode();
920 SwNodeIndex
aIdx( rNode
);
921 while( &aIdx
.GetNode() != pEndNd
)
923 if( aIdx
.GetNode().IsTxtNode() )
924 nRet
= GetTxtNodeHashValue( (SwTxtNode
&)aIdx
.GetNode(), nRet
);
932 String
sStr( GetText() );
933 for( xub_StrLen n
= 0; n
< sStr
.Len(); ++n
)
934 ( nRet
<<= 1 ) += sStr
.GetChar( n
);
940 // feste Id ? sollte aber nie auftauchen
946 const SwNode
& SwCompareLine::GetEndNode() const
948 const SwNode
* pNd
= &rNode
;
949 switch( rNode
.GetNodeType() )
952 pNd
= rNode
.EndOfSectionNode();
957 const SwSectionNode
& rSNd
= (SwSectionNode
&)rNode
;
958 const SwSection
& rSect
= rSNd
.GetSection();
959 if( CONTENT_SECTION
!= rSect
.GetType() || rSect
.IsProtect() )
960 pNd
= rNode
.EndOfSectionNode();
967 BOOL
SwCompareLine::Compare( const CompareLine
& rLine
) const
969 return CompareNode( rNode
, ((SwCompareLine
&)rLine
).rNode
);
972 BOOL
SwCompareLine::CompareNode( const SwNode
& rDstNd
, const SwNode
& rSrcNd
)
974 if( rSrcNd
.GetNodeType() != rDstNd
.GetNodeType() )
979 switch( rDstNd
.GetNodeType() )
982 bRet
= CompareTxtNd( (SwTxtNode
&)rDstNd
, (SwTxtNode
&)rSrcNd
);
987 const SwTableNode
& rTSrcNd
= (SwTableNode
&)rSrcNd
;
988 const SwTableNode
& rTDstNd
= (SwTableNode
&)rDstNd
;
990 bRet
= ( rTSrcNd
.EndOfSectionIndex() - rTSrcNd
.GetIndex() ) ==
991 ( rTDstNd
.EndOfSectionIndex() - rTDstNd
.GetIndex() );
997 const SwSectionNode
& rSSrcNd
= (SwSectionNode
&)rSrcNd
,
998 & rSDstNd
= (SwSectionNode
&)rDstNd
;
999 const SwSection
& rSrcSect
= rSSrcNd
.GetSection(),
1000 & rDstSect
= rSDstNd
.GetSection();
1001 SectionType eSrcSectType
= rSrcSect
.GetType(),
1002 eDstSectType
= rDstSect
.GetType();
1003 switch( eSrcSectType
)
1005 case CONTENT_SECTION
:
1006 bRet
= CONTENT_SECTION
== eDstSectType
&&
1007 rSrcSect
.IsProtect() == rDstSect
.IsProtect();
1008 if( bRet
&& rSrcSect
.IsProtect() )
1010 // the only have they both the same size
1011 bRet
= ( rSSrcNd
.EndOfSectionIndex() - rSSrcNd
.GetIndex() ) ==
1012 ( rSDstNd
.EndOfSectionIndex() - rSDstNd
.GetIndex() );
1016 case TOX_HEADER_SECTION
:
1017 case TOX_CONTENT_SECTION
:
1018 if( TOX_HEADER_SECTION
== eDstSectType
||
1019 TOX_CONTENT_SECTION
== eDstSectType
)
1021 // the same type of TOX?
1022 const SwTOXBase
* pSrcTOX
= rSrcSect
.GetTOXBase();
1023 const SwTOXBase
* pDstTOX
= rDstSect
.GetTOXBase();
1024 bRet
= pSrcTOX
&& pDstTOX
1025 && pSrcTOX
->GetType() == pDstTOX
->GetType()
1026 && pSrcTOX
->GetTitle() == pDstTOX
->GetTitle()
1027 && pSrcTOX
->GetTypeName() == pDstTOX
->GetTypeName()
1028 // && pSrcTOX->GetTOXName() == pDstTOX->GetTOXName()
1033 case DDE_LINK_SECTION
:
1034 case FILE_LINK_SECTION
:
1035 bRet
= eSrcSectType
== eDstSectType
&&
1036 rSrcSect
.GetLinkFileName() ==
1037 rDstSect
.GetLinkFileName();
1044 bRet
= rSrcNd
.StartOfSectionNode()->GetNodeType() ==
1045 rDstNd
.StartOfSectionNode()->GetNodeType();
1051 String
SwCompareLine::GetText() const
1054 switch( rNode
.GetNodeType() )
1057 sRet
= ((SwTxtNode
&)rNode
).GetExpandTxt();
1062 const SwNode
* pEndNd
= rNode
.EndOfSectionNode();
1063 SwNodeIndex
aIdx( rNode
);
1064 while( &aIdx
.GetNode() != pEndNd
)
1066 if( aIdx
.GetNode().IsTxtNode() )
1069 sRet
.Append( '\n' );
1070 sRet
.Append( ((SwTxtNode
&)rNode
).GetExpandTxt() );
1074 sRet
.InsertAscii( "Tabelle: ", 0 );
1078 case ND_SECTIONNODE
:
1080 sRet
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "Section - Node:" ));
1082 const SwSectionNode
& rSNd
= (SwSectionNode
&)rNode
;
1083 const SwSection
& rSect
= rSNd
.GetSection();
1084 switch( rSect
.GetType() )
1086 case CONTENT_SECTION
:
1087 if( rSect
.IsProtect() )
1088 sRet
.Append( String::CreateFromInt32(
1089 rSNd
.EndOfSectionIndex() - rSNd
.GetIndex() ));
1092 case TOX_HEADER_SECTION
:
1093 case TOX_CONTENT_SECTION
:
1095 const SwTOXBase
* pTOX
= rSect
.GetTOXBase();
1097 sRet
.Append( pTOX
->GetTitle() )
1098 .Append( pTOX
->GetTypeName() )
1099 // .Append( pTOX->GetTOXName() )
1100 .Append( String::CreateFromInt32( pTOX
->GetType() ));
1104 case DDE_LINK_SECTION
:
1105 case FILE_LINK_SECTION
:
1106 sRet
+= rSect
.GetLinkFileName();
1113 sRet
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "Grafik - Node:" ));
1116 sRet
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "OLE - Node:" ));
1122 ULONG
SwCompareLine::GetTxtNodeHashValue( const SwTxtNode
& rNd
, ULONG nVal
)
1124 String
sStr( rNd
.GetExpandTxt() );
1125 for( xub_StrLen n
= 0; n
< sStr
.Len(); ++n
)
1126 ( nVal
<<= 1 ) += sStr
.GetChar( n
);
1130 BOOL
SwCompareLine::CompareTxtNd( const SwTxtNode
& rDstNd
,
1131 const SwTxtNode
& rSrcNd
)
1134 // erstmal ganz einfach!
1135 if( rDstNd
.GetTxt() == rSrcNd
.GetTxt() )
1137 // der Text ist gleich, aber sind die "Sonderattribute" (0xFF) auch
1144 BOOL
SwCompareLine::ChangesInLine( const SwCompareLine
& rLine
,
1145 SwPaM
*& rpInsRing
, SwPaM
*& rpDelRing
) const
1148 if( ND_TEXTNODE
== rNode
.GetNodeType() &&
1149 ND_TEXTNODE
== rLine
.GetNode().GetNodeType() )
1151 SwTxtNode
& rDestNd
= *(SwTxtNode
*)rNode
.GetTxtNode();
1152 const SwTxtNode
& rSrcNd
= *rLine
.GetNode().GetTxtNode();
1154 xub_StrLen nDEnd
= rDestNd
.GetTxt().Len(), nSEnd
= rSrcNd
.GetTxt().Len();
1158 for( nStt
= 0, nEnd
= Min( nDEnd
, nSEnd
); nStt
< nEnd
; ++nStt
)
1159 if( rDestNd
.GetTxt().GetChar( nStt
) !=
1160 rSrcNd
.GetTxt().GetChar( nStt
) )
1163 while( nStt
< nDEnd
&& nStt
< nSEnd
)
1166 if( rDestNd
.GetTxt().GetChar( nDEnd
) !=
1167 rSrcNd
.GetTxt().GetChar( nSEnd
) )
1174 if( nStt
|| !nDEnd
|| !nSEnd
|| nDEnd
< rDestNd
.GetTxt().Len() ||
1175 nSEnd
< rSrcNd
.GetTxt().Len() )
1177 // jetzt ist zwischen nStt bis nDEnd das neu eingefuegte
1178 // und zwischen nStt und nSEnd das geloeschte
1179 SwDoc
* pDoc
= rDestNd
.GetDoc();
1180 SwPaM
aPam( rDestNd
, nDEnd
);
1183 SwPaM
* pTmp
= new SwPaM( *aPam
.GetPoint(), rpInsRing
);
1188 pTmp
->GetMark()->nContent
= nStt
;
1194 BOOL bUndo
= pDoc
->DoesUndo();
1195 pDoc
->DoUndo( FALSE
);
1196 SwPaM
aCpyPam( rSrcNd
, nStt
);
1198 aCpyPam
.GetPoint()->nContent
= nSEnd
;
1199 aCpyPam
.GetDoc()->CopyRange( aCpyPam
, *aPam
.GetPoint(),
1201 pDoc
->DoUndo( bUndo
);
1204 SwPaM
* pTmp
= new SwPaM( *aPam
.GetPoint(), rpDelRing
);
1209 pTmp
->GetMark()->nContent
= nDEnd
;
1213 SwPaM
* pCorr
= (SwPaM
*)rpInsRing
->GetPrev();
1214 if( *pCorr
->GetPoint() == *pTmp
->GetPoint() )
1215 *pCorr
->GetPoint() = *pTmp
->GetMark();
1224 // ----------------------------------------------------------------
1226 SwCompareData::~SwCompareData()
1230 while( pDelRing
->GetNext() != pDelRing
)
1231 delete pDelRing
->GetNext();
1236 while( pInsRing
->GetNext() != pInsRing
)
1237 delete pInsRing
->GetNext();
1242 ULONG
SwCompareData::NextIdx( const SwNode
* pNd
)
1244 if( pNd
->IsStartNode() )
1246 const SwSectionNode
* pSNd
;
1247 if( pNd
->IsTableNode() ||
1248 ( 0 != (pSNd
= pNd
->GetSectionNode() ) &&
1249 ( CONTENT_SECTION
!= pSNd
->GetSection().GetType() ||
1250 pSNd
->GetSection().IsProtect() ) ) )
1251 pNd
= pNd
->EndOfSectionNode();
1253 return pNd
->GetIndex() + 1;
1256 ULONG
SwCompareData::PrevIdx( const SwNode
* pNd
)
1258 if( pNd
->IsEndNode() )
1260 const SwSectionNode
* pSNd
;
1261 if( pNd
->StartOfSectionNode()->IsTableNode() ||
1262 ( 0 != (pSNd
= pNd
->StartOfSectionNode()->GetSectionNode() ) &&
1263 ( CONTENT_SECTION
!= pSNd
->GetSection().GetType() ||
1264 pSNd
->GetSection().IsProtect() ) ) )
1265 pNd
= pNd
->StartOfSectionNode();
1267 return pNd
->GetIndex() - 1;
1271 void SwCompareData::CheckRanges( CompareData
& rData
)
1273 const SwNodes
& rSrcNds
= ((SwCompareData
&)rData
).rDoc
.GetNodes();
1274 const SwNodes
& rDstNds
= rDoc
.GetNodes();
1276 const SwNode
& rSrcEndNd
= rSrcNds
.GetEndOfContent();
1277 const SwNode
& rDstEndNd
= rDstNds
.GetEndOfContent();
1279 ULONG nSrcSttIdx
= NextIdx( rSrcEndNd
.StartOfSectionNode() );
1280 ULONG nSrcEndIdx
= rSrcEndNd
.GetIndex();
1282 ULONG nDstSttIdx
= NextIdx( rDstEndNd
.StartOfSectionNode() );
1283 ULONG nDstEndIdx
= rDstEndNd
.GetIndex();
1285 while( nSrcSttIdx
< nSrcEndIdx
&& nDstSttIdx
< nDstEndIdx
)
1287 const SwNode
* pSrcNd
= rSrcNds
[ nSrcSttIdx
];
1288 const SwNode
* pDstNd
= rDstNds
[ nDstSttIdx
];
1289 if( !SwCompareLine::CompareNode( *pSrcNd
, *pDstNd
))
1292 nSrcSttIdx
= NextIdx( pSrcNd
);
1293 nDstSttIdx
= NextIdx( pDstNd
);
1296 nSrcEndIdx
= PrevIdx( &rSrcEndNd
);
1297 nDstEndIdx
= PrevIdx( &rDstEndNd
);
1298 while( nSrcSttIdx
< nSrcEndIdx
&& nDstSttIdx
< nDstEndIdx
)
1300 const SwNode
* pSrcNd
= rSrcNds
[ nSrcEndIdx
];
1301 const SwNode
* pDstNd
= rDstNds
[ nDstEndIdx
];
1302 if( !SwCompareLine::CompareNode( *pSrcNd
, *pDstNd
))
1305 nSrcEndIdx
= PrevIdx( pSrcNd
);
1306 nDstEndIdx
= PrevIdx( pDstNd
);
1309 while( nSrcSttIdx
<= nSrcEndIdx
)
1311 const SwNode
* pNd
= rSrcNds
[ nSrcSttIdx
];
1312 rData
.InsertLine( new SwCompareLine( *pNd
) );
1313 nSrcSttIdx
= NextIdx( pNd
);
1316 while( nDstSttIdx
<= nDstEndIdx
)
1318 const SwNode
* pNd
= rDstNds
[ nDstSttIdx
];
1319 InsertLine( new SwCompareLine( *pNd
) );
1320 nDstSttIdx
= NextIdx( pNd
);
1325 void SwCompareData::ShowInsert( ULONG nStt
, ULONG nEnd
)
1327 SwPaM
* pTmp
= new SwPaM( ((SwCompareLine
*)GetLine( nStt
))->GetNode(), 0,
1328 ((SwCompareLine
*)GetLine( nEnd
-1 ))->GetEndNode(), 0,
1333 // #i65201#: These SwPaMs are calculated smaller than needed, see comment below
1337 void SwCompareData::ShowDelete( const CompareData
& rData
, ULONG nStt
,
1338 ULONG nEnd
, ULONG nInsPos
)
1341 ((SwCompareLine
*)rData
.GetLine( nStt
))->GetNode(), 0,
1342 ((SwCompareLine
*)rData
.GetLine( nEnd
-1 ))->GetEndNode(), 1 );
1345 const CompareLine
* pLine
;
1346 if( GetLineCount() == nInsPos
)
1348 pLine
= GetLine( nInsPos
-1 );
1352 pLine
= GetLine( nInsPos
);
1354 const SwNode
* pLineNd
;
1358 pLineNd
= &((SwCompareLine
*)pLine
)->GetEndNode();
1360 pLineNd
= &((SwCompareLine
*)pLine
)->GetNode();
1364 pLineNd
= &rDoc
.GetNodes().GetEndOfContent();
1368 SwNodeIndex
aInsPos( *pLineNd
, nOffset
);
1369 SwNodeIndex
aSavePos( aInsPos
, -1 );
1371 ((SwCompareData
&)rData
).rDoc
.CopyWithFlyInFly( aRg
, 0, aInsPos
);
1375 // #i65201#: These SwPaMs are calculated when the (old) delete-redlines are hidden,
1376 // they will be inserted when the delete-redlines are shown again.
1377 // To avoid unwanted insertions of delete-redlines into these new redlines, what happens
1378 // especially at the end of the document, I reduce the SwPaM by one node.
1379 // Before the new redlines are inserted, they have to expand again.
1380 SwPaM
* pTmp
= new SwPaM( aSavePos
.GetNode(), aInsPos
.GetNode(), 0, -1, pDelRing
);
1386 SwPaM
* pCorr
= (SwPaM
*)pInsRing
->GetPrev();
1387 if( *pCorr
->GetPoint() == *pTmp
->GetPoint() )
1389 SwNodeIndex
aTmpPos( pTmp
->GetMark()->nNode
, -1 );
1390 *pCorr
->GetPoint() = SwPosition( aTmpPos
, 0 );
1395 void SwCompareData::CheckForChangesInLine( const CompareData
& rData
,
1396 ULONG
& rStt
, ULONG
& rEnd
,
1397 ULONG
& rThisStt
, ULONG
& rThisEnd
)
1399 while( rStt
< rEnd
&& rThisStt
< rThisEnd
)
1401 SwCompareLine
* pDstLn
= (SwCompareLine
*)GetLine( rThisStt
);
1402 SwCompareLine
* pSrcLn
= (SwCompareLine
*)rData
.GetLine( rStt
);
1403 if( !pDstLn
->ChangesInLine( *pSrcLn
, pInsRing
, pDelRing
) )
1411 void SwCompareData::SetRedlinesToDoc( BOOL bUseDocInfo
)
1413 SwPaM
* pTmp
= pDelRing
;
1415 // Bug #83296#: get the Author / TimeStamp from the "other"
1417 USHORT nAuthor
= rDoc
.GetRedlineAuthor();
1418 DateTime aTimeStamp
;
1419 SwDocShell
*pDocShell(rDoc
.GetDocShell());
1420 DBG_ASSERT(pDocShell
, "no SwDocShell");
1422 uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
1423 pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
1424 uno::Reference
<document::XDocumentProperties
> xDocProps(
1425 xDPS
->getDocumentProperties());
1426 DBG_ASSERT(xDocProps
.is(), "Doc has no DocumentProperties");
1428 if( bUseDocInfo
&& xDocProps
.is() ) {
1429 String
aTmp( 1 == xDocProps
->getEditingCycles()
1430 ? xDocProps
->getAuthor()
1431 : xDocProps
->getModifiedBy() );
1432 util::DateTime
uDT( 1 == xDocProps
->getEditingCycles()
1433 ? xDocProps
->getCreationDate()
1434 : xDocProps
->getModificationDate() );
1435 Date
d(uDT
.Day
, uDT
.Month
, uDT
.Year
);
1436 Time
t(uDT
.Hours
, uDT
.Minutes
, uDT
.Seconds
, uDT
.HundredthSeconds
);
1441 nAuthor
= rDoc
.InsertRedlineAuthor( aTmp
);
1449 SwRedlineData
aRedlnData( nsRedlineType_t::REDLINE_DELETE
, nAuthor
, aTimeStamp
,
1452 // #i65201#: Expand again, see comment above.
1453 if( pTmp
->GetPoint()->nContent
== 0 )
1455 pTmp
->GetPoint()->nNode
++;
1456 pTmp
->GetPoint()->nContent
.Assign( pTmp
->GetCntntNode(), 0 );
1459 rDoc
.DeleteRedline( *pTmp
, false, USHRT_MAX
);
1461 if( rDoc
.DoesUndo() )
1462 rDoc
.AppendUndo( new SwUndoCompDoc( *pTmp
, FALSE
));
1463 rDoc
.AppendRedline( new SwRedline( aRedlnData
, *pTmp
), true );
1465 } while( pDelRing
!= ( pTmp
= (SwPaM
*)pTmp
->GetNext() ));
1472 if( pTmp
->GetPoint()->nContent
== 0 )
1474 pTmp
->GetPoint()->nNode
++;
1475 pTmp
->GetPoint()->nContent
.Assign( pTmp
->GetCntntNode(), 0 );
1477 } while( pInsRing
!= ( pTmp
= (SwPaM
*)pTmp
->GetNext() ));
1478 SwRedlineData
aRedlnData( nsRedlineType_t::REDLINE_INSERT
, nAuthor
, aTimeStamp
,
1481 // zusammenhaengende zusammenfassen
1482 if( pTmp
->GetNext() != pInsRing
)
1484 const SwCntntNode
* pCNd
;
1486 SwPosition
& rSttEnd
= *pTmp
->End(),
1487 & rEndStt
= *((SwPaM
*)pTmp
->GetNext())->Start();
1488 if( rSttEnd
== rEndStt
||
1489 (!rEndStt
.nContent
.GetIndex() &&
1490 rEndStt
.nNode
.GetIndex() - 1 == rSttEnd
.nNode
.GetIndex() &&
1491 0 != ( pCNd
= rSttEnd
.nNode
.GetNode().GetCntntNode() )
1492 ? rSttEnd
.nContent
.GetIndex() == pCNd
->Len()
1495 if( pTmp
->GetNext() == pInsRing
)
1497 // liegen hintereinander also zusammen fassen
1498 rEndStt
= *pTmp
->Start();
1504 // liegen hintereinander also zusammen fassen
1505 rSttEnd
= *((SwPaM
*)pTmp
->GetNext())->End();
1506 delete pTmp
->GetNext();
1510 pTmp
= (SwPaM
*)pTmp
->GetNext();
1511 } while( pInsRing
!= pTmp
);
1515 if( rDoc
.AppendRedline( new SwRedline( aRedlnData
, *pTmp
), true) &&
1517 rDoc
.AppendUndo( new SwUndoCompDoc( *pTmp
, TRUE
));
1518 } while( pInsRing
!= ( pTmp
= (SwPaM
*)pTmp
->GetNext() ));
1526 // returnt (?die Anzahl der Unterschiede?) ob etwas unterschiedlich ist
1527 long SwDoc::CompareDoc( const SwDoc
& rDoc
)
1534 StartUndo(UNDO_EMPTY
, NULL
);
1535 BOOL bDocWasModified
= IsModified();
1536 SwDoc
& rSrcDoc
= (SwDoc
&)rDoc
;
1537 BOOL bSrcModified
= rSrcDoc
.IsModified();
1539 RedlineMode_t eSrcRedlMode
= rSrcDoc
.GetRedlineMode();
1540 rSrcDoc
.SetRedlineMode( nsRedlineMode_t::REDLINE_SHOW_INSERT
);
1541 SetRedlineMode((RedlineMode_t
)(nsRedlineMode_t::REDLINE_ON
| nsRedlineMode_t::REDLINE_SHOW_INSERT
));
1543 SwCompareData
aD0( rSrcDoc
);
1544 SwCompareData
aD1( *this );
1546 aD1
.CompareLines( aD0
);
1548 nRet
= aD1
.ShowDiffs( aD0
);
1552 SetRedlineMode((RedlineMode_t
)(nsRedlineMode_t::REDLINE_ON
|
1553 nsRedlineMode_t::REDLINE_SHOW_INSERT
| nsRedlineMode_t::REDLINE_SHOW_DELETE
));
1555 aD1
.SetRedlinesToDoc( !bDocWasModified
);
1559 rSrcDoc
.SetRedlineMode( eSrcRedlMode
);
1560 SetRedlineMode((RedlineMode_t
)(nsRedlineMode_t::REDLINE_SHOW_INSERT
| nsRedlineMode_t::REDLINE_SHOW_DELETE
));
1563 rSrcDoc
.ResetModified();
1565 EndUndo(UNDO_EMPTY
, NULL
);
1571 typedef void (SwDoc::*FNInsUndo
)( SwUndo
* );
1573 class _SaveMergeRedlines
: public Ring
1575 const SwRedline
* pSrcRedl
;
1576 SwRedline
* pDestRedl
;
1578 _SaveMergeRedlines( const SwNode
& rDstNd
,
1579 const SwRedline
& rSrcRedl
, Ring
* pRing
);
1580 USHORT
InsertRedline( FNInsUndo pFn
);
1582 SwRedline
* GetDestRedline() { return pDestRedl
; }
1585 _SaveMergeRedlines::_SaveMergeRedlines( const SwNode
& rDstNd
,
1586 const SwRedline
& rSrcRedl
, Ring
* pRing
)
1587 : Ring( pRing
), pSrcRedl( &rSrcRedl
)
1589 SwPosition
aPos( rDstNd
);
1591 const SwPosition
* pStt
= rSrcRedl
.Start();
1592 if( rDstNd
.IsCntntNode() )
1593 aPos
.nContent
.Assign( ((SwCntntNode
*)&rDstNd
), pStt
->nContent
.GetIndex() );
1594 pDestRedl
= new SwRedline( rSrcRedl
.GetRedlineData(), aPos
);
1596 if( nsRedlineType_t::REDLINE_DELETE
== pDestRedl
->GetType() )
1598 // den Bereich als geloescht kennzeichnen
1599 const SwPosition
* pEnd
= pStt
== rSrcRedl
.GetPoint()
1600 ? rSrcRedl
.GetMark()
1601 : rSrcRedl
.GetPoint();
1603 pDestRedl
->SetMark();
1604 pDestRedl
->GetPoint()->nNode
+= pEnd
->nNode
.GetIndex() -
1605 pStt
->nNode
.GetIndex();
1606 pDestRedl
->GetPoint()->nContent
.Assign( pDestRedl
->GetCntntNode(),
1607 pEnd
->nContent
.GetIndex() );
1611 USHORT
_SaveMergeRedlines::InsertRedline( FNInsUndo pFn
)
1614 SwDoc
* pDoc
= pDestRedl
->GetDoc();
1616 if( nsRedlineType_t::REDLINE_INSERT
== pDestRedl
->GetType() )
1618 // der Teil wurde eingefuegt, also kopiere ihn aus dem SourceDoc
1619 BOOL bUndo
= pDoc
->DoesUndo();
1620 pDoc
->DoUndo( FALSE
);
1622 SwNodeIndex
aSaveNd( pDestRedl
->GetPoint()->nNode
, -1 );
1623 xub_StrLen nSaveCnt
= pDestRedl
->GetPoint()->nContent
.GetIndex();
1625 RedlineMode_t eOld
= pDoc
->GetRedlineMode();
1626 pDoc
->SetRedlineMode_intern((RedlineMode_t
)(eOld
| nsRedlineMode_t::REDLINE_IGNORE
));
1628 pSrcRedl
->GetDoc()->CopyRange(
1629 *const_cast<SwPaM
*>(static_cast<const SwPaM
*>(pSrcRedl
)),
1630 *pDestRedl
->GetPoint(), false );
1632 pDoc
->SetRedlineMode_intern( eOld
);
1633 pDoc
->DoUndo( bUndo
);
1635 pDestRedl
->SetMark();
1637 pDestRedl
->GetMark()->nNode
= aSaveNd
;
1638 pDestRedl
->GetMark()->nContent
.Assign( aSaveNd
.GetNode().GetCntntNode(),
1641 if( GetPrev() != this )
1643 SwPaM
* pTmpPrev
= ((_SaveMergeRedlines
*)GetPrev())->pDestRedl
;
1644 if( pTmpPrev
&& *pTmpPrev
->GetPoint() == *pDestRedl
->GetPoint() )
1645 *pTmpPrev
->GetPoint() = *pDestRedl
->GetMark();
1650 //JP 21.09.98: Bug 55909
1651 // falls im Doc auf gleicher Pos aber schon ein geloeschter oder
1652 // eingefuegter ist, dann muss dieser gesplittet werden!
1653 SwPosition
* pDStt
= pDestRedl
->GetMark(),
1654 * pDEnd
= pDestRedl
->GetPoint();
1657 // zur StartPos das erste Redline suchen
1658 if( !pDoc
->GetRedline( *pDStt
, &n
) && n
)
1661 const SwRedlineTbl
& rRedlineTbl
= pDoc
->GetRedlineTbl();
1662 for( ; n
< rRedlineTbl
.Count(); ++n
)
1664 SwRedline
* pRedl
= rRedlineTbl
[ n
];
1665 SwPosition
* pRStt
= pRedl
->Start(),
1666 * pREnd
= pRStt
== pRedl
->GetPoint() ? pRedl
->GetMark()
1667 : pRedl
->GetPoint();
1668 if( nsRedlineType_t::REDLINE_DELETE
== pRedl
->GetType() ||
1669 nsRedlineType_t::REDLINE_INSERT
== pRedl
->GetType() )
1671 SwComparePosition eCmpPos
= ComparePosition( *pDStt
, *pDEnd
, *pRStt
, *pREnd
);
1674 case POS_COLLIDE_START
:
1680 delete pDestRedl
, pDestRedl
= 0;
1681 // break; -> kein break !!!!
1683 case POS_COLLIDE_END
:
1685 n
= rRedlineTbl
.Count();
1690 SwRedline
* pCpyRedl
= new SwRedline(
1691 pDestRedl
->GetRedlineData(), *pDStt
);
1692 pCpyRedl
->SetMark();
1693 *pCpyRedl
->GetPoint() = *pRStt
;
1695 SwUndoCompDoc
* pUndo
= pDoc
->DoesUndo()
1696 ? new SwUndoCompDoc( *pCpyRedl
) : 0;
1698 // now modify doc: append redline, undo (and count)
1699 pDoc
->AppendRedline( pCpyRedl
, true );
1701 (pDoc
->*pFn
)( pUndo
);
1706 // dann solle man neu anfangen
1711 case POS_OVERLAP_BEFORE
:
1715 case POS_OVERLAP_BEHIND
:
1720 else if( *pDEnd
<= *pRStt
)
1728 SwUndoCompDoc
* pUndo
= pDoc
->DoesUndo() ? new SwUndoCompDoc( *pDestRedl
) : 0;
1730 // now modify doc: append redline, undo (and count)
1731 bool bRedlineAccepted
= pDoc
->AppendRedline( pDestRedl
, true );
1733 (pDoc
->*pFn
)( pUndo
);
1736 // if AppendRedline has deleted our redline, we may not keep a
1738 if( ! bRedlineAccepted
)
1744 // merge zweier Dokumente
1745 long SwDoc::MergeDoc( const SwDoc
& rDoc
)
1752 StartUndo(UNDO_EMPTY
, NULL
);
1754 SwDoc
& rSrcDoc
= (SwDoc
&)rDoc
;
1755 BOOL bSrcModified
= rSrcDoc
.IsModified();
1757 RedlineMode_t eSrcRedlMode
= rSrcDoc
.GetRedlineMode();
1758 rSrcDoc
.SetRedlineMode( nsRedlineMode_t::REDLINE_SHOW_DELETE
);
1759 SetRedlineMode( nsRedlineMode_t::REDLINE_SHOW_DELETE
);
1761 SwCompareData
aD0( rSrcDoc
);
1762 SwCompareData
aD1( *this );
1764 aD1
.CompareLines( aD0
);
1766 if( !aD1
.HasDiffs( aD0
) )
1768 // jetzt wollen wir alle Redlines aus dem SourceDoc zu uns bekommen
1770 // suche alle Insert - Redlines aus dem SourceDoc und bestimme
1771 // deren Position im DestDoc
1772 _SaveMergeRedlines
* pRing
= 0;
1773 const SwRedlineTbl
& rSrcRedlTbl
= rSrcDoc
.GetRedlineTbl();
1774 ULONG nEndOfExtra
= rSrcDoc
.GetNodes().GetEndOfExtras().GetIndex();
1775 ULONG nMyEndOfExtra
= GetNodes().GetEndOfExtras().GetIndex();
1776 for( USHORT n
= 0; n
< rSrcRedlTbl
.Count(); ++n
)
1778 const SwRedline
* pRedl
= rSrcRedlTbl
[ n
];
1779 ULONG nNd
= pRedl
->GetPoint()->nNode
.GetIndex();
1780 RedlineType_t eType
= pRedl
->GetType();
1781 if( nEndOfExtra
< nNd
&&
1782 ( nsRedlineType_t::REDLINE_INSERT
== eType
|| nsRedlineType_t::REDLINE_DELETE
== eType
))
1784 const SwNode
* pDstNd
= GetNodes()[
1785 nMyEndOfExtra
+ nNd
- nEndOfExtra
];
1787 // Position gefunden. Dann muss im DestDoc auch
1788 // in der Line das Redline eingefuegt werden
1789 _SaveMergeRedlines
* pTmp
= new _SaveMergeRedlines(
1790 *pDstNd
, *pRedl
, pRing
);
1798 // dann alle ins DestDoc ueber nehmen
1799 rSrcDoc
.SetRedlineMode((RedlineMode_t
)(nsRedlineMode_t::REDLINE_SHOW_INSERT
| nsRedlineMode_t::REDLINE_SHOW_DELETE
));
1801 SetRedlineMode((RedlineMode_t
)(
1802 nsRedlineMode_t::REDLINE_ON
|
1803 nsRedlineMode_t::REDLINE_SHOW_INSERT
|
1804 nsRedlineMode_t::REDLINE_SHOW_DELETE
));
1806 _SaveMergeRedlines
* pTmp
= pRing
;
1809 nRet
+= pTmp
->InsertRedline( &SwDoc::AppendUndo
);
1810 } while( pRing
!= ( pTmp
= (_SaveMergeRedlines
*)pTmp
->GetNext() ));
1812 while( pRing
!= pRing
->GetNext() )
1813 delete pRing
->GetNext();
1818 rSrcDoc
.SetRedlineMode( eSrcRedlMode
);
1820 rSrcDoc
.ResetModified();
1822 SetRedlineMode((RedlineMode_t
)(nsRedlineMode_t::REDLINE_SHOW_INSERT
| nsRedlineMode_t::REDLINE_SHOW_DELETE
));
1824 EndUndo(UNDO_EMPTY
, NULL
);