xref: /trunk/main/sw/source/core/doc/doccomp.cxx (revision dec99bbd)
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:
CompareLine()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 );
GetIndex(sal_uLong nLine) const103 	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 );
GetChanged(sal_uLong nLine) const108 	sal_Bool GetChanged( sal_uLong nLine ) const
109 		{
110 			return (pChangedFlag && nLine < aLines.Count())
111 				? pChangedFlag[ nLine ]
112 				: 0;
113 		}
114 
GetLineCount() const115 	sal_uLong GetLineCount() const		{ return aLines.Count(); }
GetLineOffset() const116 	sal_uLong GetLineOffset() const  	{ return nSttLineNum; }
GetLine(sal_uLong nLine) const117 	const CompareLine* GetLine( sal_uLong nLine ) const
118 			{ return aLines.GetObject( nLine ); }
InsertLine(CompareLine * pLine)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 
_HashDataHash::_HashData130 		_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 
GetCount() const144 	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 
GetIndex(sal_uLong n) const160 		sal_uLong GetIndex( sal_uLong n ) const { return pIndex[ n ]; }
GetLineNum(sal_uLong n) const161 		sal_uLong GetLineNum( sal_uLong n ) const { return pLineNum[ n ]; }
GetCount() const162 		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 
~CompareLine()196 CompareLine::~CompareLine() {}
197 
198 // ----------------------------------------------------------------------
199 
CompareData()200 CompareData::CompareData()
201 	: pIndex( 0 ), pChangedFlag( 0 ), nSttLineNum( 0 )
202 {
203 }
204 
~CompareData()205 CompareData::~CompareData()
206 {
207     delete[] pIndex;
208     delete[] pChangedFlag;
209 }
210 
SetIndex(sal_uLong nLine,sal_uLong nIndex)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 
SetChanged(sal_uLong nLine,sal_Bool bFlag)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 
CompareLines(CompareData & rData)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 
ShowDiffs(const CompareData & rData)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 
HasDiffs(const CompareData & rData) const280 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 
ShowInsert(sal_uLong,sal_uLong)298 void CompareData::ShowInsert( sal_uLong, sal_uLong )
299 {
300 }
301 
ShowDelete(const CompareData &,sal_uLong,sal_uLong,sal_uLong)302 void CompareData::ShowDelete( const CompareData&, sal_uLong, sal_uLong, sal_uLong )
303 {
304 }
305 
CheckForChangesInLine(const CompareData &,sal_uLong &,sal_uLong &,sal_uLong &,sal_uLong &)306 void CompareData::CheckForChangesInLine( const CompareData& ,
307 									sal_uLong&, sal_uLong&, sal_uLong&, sal_uLong& )
308 {
309 }
310 
311 // ----------------------------------------------------------------------
312 
Hash(sal_uLong nSize)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 
~Hash()362 Hash::~Hash()
363 {
364     delete[] pHashArr;
365     delete[] pDataArr;
366 }
367 
CalcHashValue(CompareData & rData)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 
Compare(sal_uLong nDiff,CompareData & rData1,CompareData & rData2)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 
CountDifference(const CompareData & rData,sal_uLong * pCounts)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 
SetDiscard(const CompareData & rData,sal_Char * pDiscard,sal_uLong * pCounts)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 
CheckDiscard(sal_uLong nLen,sal_Char * pDiscard)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 
MovedData(CompareData & rData,sal_Char * pDiscard)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 
~MovedData()615 Compare::MovedData::~MovedData()
616 {
617     delete [] pIndex;
618     delete [] pLineNum;
619 }
620 
621 // ----------------------------------------------------------------------
622 
623 	// Suche die verschobenen Lines
CompareSequence(CompareData & rD1,CompareData & rD2,const MovedData & rMD1,const MovedData & rMD2)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 
~CompareSequence()637 Compare::CompareSequence::~CompareSequence()
638 {
639     delete [] pMemory;
640 }
641 
Compare(sal_uLong nStt1,sal_uLong nEnd1,sal_uLong nStt2,sal_uLong nEnd2)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 
CheckDiag(sal_uLong nStt1,sal_uLong nEnd1,sal_uLong nStt2,sal_uLong nEnd2,sal_uLong * pCost)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 
ShiftBoundaries(CompareData & rData1,CompareData & rData2)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 
GetNode() const859 	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:
SwCompareData(SwDoc & rD)885 	SwCompareData( SwDoc& rD ) : rDoc( rD ), pInsRing(0), pDelRing(0) {}
886 	virtual ~SwCompareData();
887 
888 	void SetRedlinesToDoc( sal_Bool bUseDocInfo );
889 };
890 
891 // ----------------------------------------------------------------
892 
SwCompareLine(const SwNode & rNd)893 SwCompareLine::SwCompareLine( const SwNode& rNd )
894 	: rNode( rNd )
895 {
896 }
897 
~SwCompareLine()898 SwCompareLine::~SwCompareLine()
899 {
900 }
901 
GetHashValue() const902 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 
GetEndNode() const940 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 
Compare(const CompareLine & rLine) const961 sal_Bool SwCompareLine::Compare( const CompareLine& rLine ) const
962 {
963 	return CompareNode( rNode, ((SwCompareLine&)rLine).rNode );
964 }
965 
966 namespace
967 {
SimpleTableToText(const SwNode & rNode)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 
CompareNode(const SwNode & rDstNd,const SwNode & rSrcNd)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 
GetText() const1084 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 
GetTxtNodeHashValue(const SwTxtNode & rNd,sal_uLong nVal)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 
CompareTxtNd(const SwTxtNode & rDstNd,const SwTxtNode & rSrcNd)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 
ChangesInLine(const SwCompareLine & rLine,SwPaM * & rpInsRing,SwPaM * & rpDelRing) const1166 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 
~SwCompareData()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 
NextIdx(const SwNode * pNd)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 
PrevIdx(const SwNode * pNd)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 
CheckRanges(CompareData & rData)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 
ShowInsert(sal_uLong nStt,sal_uLong nEnd)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 
ShowDelete(const CompareData & rData,sal_uLong nStt,sal_uLong nEnd,sal_uLong nInsPos)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 
CheckForChangesInLine(const CompareData & rData,sal_uLong & rStt,sal_uLong & rEnd,sal_uLong & rThisStt,sal_uLong & rThisEnd)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 
SetRedlinesToDoc(sal_Bool bUseDocInfo)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
CompareDoc(const SwDoc & rDoc)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 
GetDestRedline()1631 	SwRedline* GetDestRedline() { return pDestRedl; }
1632 };
1633 
_SaveMergeRedlines(const SwNode & rDstNd,const SwRedline & rSrcRedl,Ring * pRing)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 
InsertRedline()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
MergeDoc(const SwDoc & rDoc)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