2010-10-14 08:30:41 +02:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2000-09-18 23:08:29 +00:00
|
|
|
/*************************************************************************
|
|
|
|
*
|
2008-04-10 12:07:37 +00:00
|
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
2000-09-18 23:08:29 +00:00
|
|
|
*
|
2010-02-12 15:01:35 +01:00
|
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
2000-09-18 23:08:29 +00:00
|
|
|
*
|
2008-04-10 12:07:37 +00:00
|
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
2000-09-18 23:08:29 +00:00
|
|
|
*
|
2008-04-10 12:07:37 +00:00
|
|
|
* This file is part of OpenOffice.org.
|
2000-09-18 23:08:29 +00:00
|
|
|
*
|
2008-04-10 12:07:37 +00:00
|
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
|
|
* only, as published by the Free Software Foundation.
|
2000-09-18 23:08:29 +00:00
|
|
|
*
|
2008-04-10 12:07:37 +00:00
|
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Lesser General Public License version 3 for more details
|
|
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
2000-09-18 23:08:29 +00:00
|
|
|
*
|
2008-04-10 12:07:37 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
|
|
* <http://www.openoffice.org/license.html>
|
|
|
|
* for a copy of the LGPLv3 License.
|
2000-09-18 23:08:29 +00:00
|
|
|
*
|
|
|
|
************************************************************************/
|
|
|
|
|
2006-09-16 19:50:37 +00:00
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
#include <hintids.hxx>
|
2004-01-06 17:14:43 +00:00
|
|
|
#include <vcl/vclenum.hxx>
|
2010-01-08 18:32:51 +01:00
|
|
|
#include <editeng/crsditem.hxx>
|
|
|
|
#include <editeng/colritem.hxx>
|
|
|
|
#include <editeng/boxitem.hxx>
|
2011-12-22 17:27:32 +01:00
|
|
|
#include <editeng/svxenum.hxx>
|
2010-01-08 18:32:51 +01:00
|
|
|
#include <editeng/udlnitem.hxx>
|
2011-12-22 17:27:32 +01:00
|
|
|
#include <swmodule.hxx>
|
2000-09-18 23:08:29 +00:00
|
|
|
#include <doc.hxx>
|
2010-11-25 14:31:08 +01:00
|
|
|
#include <IDocumentUndoRedo.hxx>
|
2000-09-18 23:08:29 +00:00
|
|
|
#include <docary.hxx>
|
|
|
|
#include <pam.hxx>
|
|
|
|
#include <ndtxt.hxx>
|
|
|
|
#include <redline.hxx>
|
2010-12-15 09:14:16 +01:00
|
|
|
#include <UndoRedline.hxx>
|
2001-09-27 12:42:58 +00:00
|
|
|
#include <section.hxx>
|
|
|
|
#include <tox.hxx>
|
2008-02-26 13:05:40 +00:00
|
|
|
#include <docsh.hxx>
|
|
|
|
|
|
|
|
#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
|
|
|
|
#include <com/sun/star/document/XDocumentProperties.hpp>
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2010-12-12 08:04:28 -08:00
|
|
|
#include <vector>
|
|
|
|
|
2011-12-22 17:27:32 +01:00
|
|
|
#include <set>
|
|
|
|
#include <cctype>
|
|
|
|
|
2007-09-27 07:33:25 +00:00
|
|
|
using namespace ::com::sun::star;
|
|
|
|
|
2010-12-12 08:04:28 -08:00
|
|
|
using ::std::vector;
|
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
class CompareLine
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CompareLine() {}
|
|
|
|
virtual ~CompareLine();
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
virtual sal_uLong GetHashValue() const = 0;
|
2012-10-20 23:12:12 +09:00
|
|
|
virtual bool Compare( const CompareLine& rLine ) const = 0;
|
2000-09-18 23:08:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class CompareData
|
|
|
|
{
|
2010-12-12 08:04:28 -08:00
|
|
|
size_t* pIndex;
|
|
|
|
bool* pChangedFlag;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
protected:
|
2010-12-12 08:04:28 -08:00
|
|
|
vector< CompareLine* > aLines;
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nSttLineNum;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// Truncate beginning and end and add all others to the LinesArray
|
2000-09-18 23:08:29 +00:00
|
|
|
virtual void CheckRanges( CompareData& ) = 0;
|
|
|
|
|
|
|
|
public:
|
|
|
|
CompareData();
|
|
|
|
virtual ~CompareData();
|
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// Are there differences?
|
2012-10-20 23:12:12 +09:00
|
|
|
bool HasDiffs( const CompareData& rData ) const;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// Triggers the comparison and creation of two documents
|
2000-09-18 23:08:29 +00:00
|
|
|
void CompareLines( CompareData& rData );
|
2011-11-04 14:46:42 +01:00
|
|
|
// Display the differences - calls the methods ShowInsert and ShowDelete.
|
|
|
|
// These are passed the start and end line number.
|
|
|
|
// Displaying the actually content is to be handled by the subclass!
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong ShowDiffs( const CompareData& rData );
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
virtual void ShowInsert( sal_uLong nStt, sal_uLong nEnd );
|
|
|
|
virtual void ShowDelete( const CompareData& rData, sal_uLong nStt,
|
|
|
|
sal_uLong nEnd, sal_uLong nInsPos );
|
2000-09-18 23:08:29 +00:00
|
|
|
virtual void CheckForChangesInLine( const CompareData& rData,
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong& nStt, sal_uLong& nEnd,
|
|
|
|
sal_uLong& nThisStt, sal_uLong& nThisEnd );
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// Set non-ambiguous index for a line. Same lines have the same index, even in the other CompareData!
|
2010-12-13 05:50:06 -08:00
|
|
|
void SetIndex( size_t nLine, size_t nIndex );
|
2010-12-12 08:04:28 -08:00
|
|
|
size_t GetIndex( size_t nLine ) const
|
|
|
|
{ return nLine < aLines.size() ? pIndex[ nLine ] : 0; }
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// Set/get of a line has changed
|
2010-12-12 08:04:28 -08:00
|
|
|
void SetChanged( size_t nLine, bool bFlag = true );
|
|
|
|
bool GetChanged( size_t nLine ) const
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2010-12-12 08:04:28 -08:00
|
|
|
return (pChangedFlag && nLine < aLines.size())
|
2000-09-18 23:08:29 +00:00
|
|
|
? pChangedFlag[ nLine ]
|
|
|
|
: 0;
|
|
|
|
}
|
|
|
|
|
2010-12-12 08:04:28 -08:00
|
|
|
size_t GetLineCount() const { return aLines.size(); }
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong GetLineOffset() const { return nSttLineNum; }
|
2010-12-12 08:04:28 -08:00
|
|
|
const CompareLine* GetLine( size_t nLine ) const
|
|
|
|
{ return aLines[ nLine ]; }
|
2000-09-18 23:08:29 +00:00
|
|
|
void InsertLine( CompareLine* pLine )
|
2010-12-12 08:04:28 -08:00
|
|
|
{ aLines.push_back( pLine ); }
|
2000-09-18 23:08:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class Hash
|
|
|
|
{
|
|
|
|
struct _HashData
|
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nNext, nHash;
|
2000-09-18 23:08:29 +00:00
|
|
|
const CompareLine* pLine;
|
|
|
|
|
|
|
|
_HashData()
|
|
|
|
: nNext( 0 ), nHash( 0 ), pLine(0) {}
|
|
|
|
};
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong* pHashArr;
|
2000-09-18 23:08:29 +00:00
|
|
|
_HashData* pDataArr;
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nCount, nPrime;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
public:
|
2011-01-17 15:06:54 +01:00
|
|
|
Hash( sal_uLong nSize );
|
2000-09-18 23:08:29 +00:00
|
|
|
~Hash();
|
|
|
|
|
|
|
|
void CalcHashValue( CompareData& rData );
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong GetCount() const { return nCount; }
|
2000-09-18 23:08:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class Compare
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
class MovedData
|
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong* pIndex;
|
|
|
|
sal_uLong* pLineNum;
|
|
|
|
sal_uLong nCount;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
MovedData( CompareData& rData, sal_Char* pDiscard );
|
|
|
|
~MovedData();
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong GetIndex( sal_uLong n ) const { return pIndex[ n ]; }
|
|
|
|
sal_uLong GetLineNum( sal_uLong n ) const { return pLineNum[ n ]; }
|
|
|
|
sal_uLong GetCount() const { return nCount; }
|
2000-09-18 23:08:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
private:
|
2011-11-04 14:46:42 +01:00
|
|
|
// Look for the moved lines
|
2000-09-18 23:08:29 +00:00
|
|
|
class CompareSequence
|
|
|
|
{
|
|
|
|
CompareData &rData1, &rData2;
|
|
|
|
const MovedData &rMoved1, &rMoved2;
|
|
|
|
long *pMemory, *pFDiag, *pBDiag;
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
void Compare( sal_uLong nStt1, sal_uLong nEnd1, sal_uLong nStt2, sal_uLong nEnd2 );
|
|
|
|
sal_uLong CheckDiag( sal_uLong nStt1, sal_uLong nEnd1,
|
|
|
|
sal_uLong nStt2, sal_uLong nEnd2, sal_uLong* pCost );
|
2000-09-18 23:08:29 +00:00
|
|
|
public:
|
|
|
|
CompareSequence( CompareData& rData1, CompareData& rData2,
|
|
|
|
const MovedData& rD1, const MovedData& rD2 );
|
|
|
|
~CompareSequence();
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
static void CountDifference( const CompareData& rData, sal_uLong* pCounts );
|
2000-09-18 23:08:29 +00:00
|
|
|
static void SetDiscard( const CompareData& rData,
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_Char* pDiscard, sal_uLong* pCounts );
|
|
|
|
static void CheckDiscard( sal_uLong nLen, sal_Char* pDiscard );
|
|
|
|
static sal_uLong SetChangedFlag( CompareData& rData, sal_Char* pDiscard, int bFirst );
|
2000-09-18 23:08:29 +00:00
|
|
|
static void ShiftBoundaries( CompareData& rData1, CompareData& rData2 );
|
|
|
|
|
|
|
|
public:
|
2011-01-17 15:06:54 +01:00
|
|
|
Compare( sal_uLong nDiff, CompareData& rData1, CompareData& rData2 );
|
2000-09-18 23:08:29 +00:00
|
|
|
};
|
|
|
|
|
2011-12-22 17:27:32 +01:00
|
|
|
class ArrayComparator
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual bool Compare( int nIdx1, int nIdx2 ) const = 0;
|
|
|
|
virtual int GetLen1() const = 0;
|
|
|
|
virtual int GetLen2() const = 0;
|
2012-02-19 19:42:51 +00:00
|
|
|
virtual ~ArrayComparator() {}
|
2011-12-22 17:27:32 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
// Consider two lines equal if similar enough (e.g. look like different
|
|
|
|
// versions of the same paragraph)
|
|
|
|
class LineArrayComparator : public ArrayComparator
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
int nLen1, nLen2;
|
|
|
|
const CompareData &rData1, &rData2;
|
|
|
|
int nFirst1, nFirst2;
|
|
|
|
|
|
|
|
public:
|
|
|
|
LineArrayComparator( const CompareData &rD1, const CompareData &rD2,
|
|
|
|
int nStt1, int nEnd1, int nStt2, int nEnd2 );
|
|
|
|
|
|
|
|
virtual bool Compare( int nIdx1, int nIdx2 ) const;
|
|
|
|
virtual int GetLen1() const { return nLen1; }
|
|
|
|
virtual int GetLen2() const { return nLen2; }
|
|
|
|
};
|
|
|
|
|
|
|
|
class WordArrayComparator : public ArrayComparator
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
const SwTxtNode *pTxtNd1, *pTxtNd2;
|
|
|
|
int *pPos1, *pPos2;
|
|
|
|
int nCnt1, nCnt2; // number of words
|
|
|
|
|
|
|
|
void CalcPositions( int *pPos, const SwTxtNode *pTxtNd, int &nCnt );
|
|
|
|
|
|
|
|
public:
|
|
|
|
WordArrayComparator( const SwTxtNode *pNode1, const SwTxtNode *pNode2 );
|
|
|
|
~WordArrayComparator();
|
|
|
|
|
|
|
|
virtual bool Compare( int nIdx1, int nIdx2 ) const;
|
|
|
|
virtual int GetLen1() const { return nCnt1; }
|
|
|
|
virtual int GetLen2() const { return nCnt2; }
|
|
|
|
int GetCharSequence( const int *pWordLcs1, const int *pWordLcs2,
|
|
|
|
int *pSubseq1, int *pSubseq2, int nLcsLen );
|
|
|
|
};
|
|
|
|
|
|
|
|
class CharArrayComparator : public ArrayComparator
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
const SwTxtNode *pTxtNd1, *pTxtNd2;
|
|
|
|
|
|
|
|
public:
|
|
|
|
CharArrayComparator( const SwTxtNode *pNode1, const SwTxtNode *pNode2 )
|
|
|
|
: pTxtNd1( pNode1 ), pTxtNd2( pNode2 )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool Compare( int nIdx1, int nIdx2 ) const;
|
|
|
|
virtual int GetLen1() const { return pTxtNd1->GetTxt().Len(); }
|
|
|
|
virtual int GetLen2() const { return pTxtNd2->GetTxt().Len(); }
|
|
|
|
};
|
|
|
|
|
|
|
|
// Options set in Tools->Options->Writer->Comparison
|
|
|
|
struct CmpOptionsContainer
|
|
|
|
{
|
|
|
|
SvxCompareMode eCmpMode;
|
|
|
|
int nIgnoreLen;
|
|
|
|
bool bUseRsid;
|
|
|
|
} CmpOptions;
|
|
|
|
|
|
|
|
class CommonSubseq
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
int *pData;
|
|
|
|
int nSize;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
ArrayComparator &rCmp;
|
|
|
|
|
|
|
|
CommonSubseq( ArrayComparator &rComparator, int nMaxSize )
|
|
|
|
: nSize( nMaxSize ), rCmp( rComparator )
|
|
|
|
{
|
|
|
|
pData = new int[ nSize ];
|
|
|
|
}
|
|
|
|
|
|
|
|
~CommonSubseq()
|
|
|
|
{
|
|
|
|
delete[] pData;
|
|
|
|
}
|
|
|
|
|
|
|
|
int FindLCS( int *pLcs1 = 0, int *pLcs2 = 0, int nStt1 = 0,
|
|
|
|
int nEnd1 = 0, int nStt2 = 0, int nEnd2 = 0 );
|
|
|
|
|
|
|
|
public:
|
|
|
|
int IgnoreIsolatedPieces( int *pLcs1, int *pLcs2, int nLen1, int nLen2,
|
|
|
|
int nLcsLen, int nPieceLen );
|
|
|
|
};
|
|
|
|
|
|
|
|
// Use Hirschberg's algrithm to find LCS in linear space
|
|
|
|
class LgstCommonSubseq: public CommonSubseq
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
static const int CUTOFF = 1<<20; // Stop recursion at this value
|
|
|
|
|
|
|
|
int *pL1, *pL2;
|
|
|
|
int *pBuff1, *pBuff2;
|
|
|
|
|
|
|
|
void FindL( int *pL, int nStt1, int nEnd1, int nStt2, int nEnd2 );
|
|
|
|
int HirschbergLCS( int *pLcs1, int *pLcs2, int nStt1, int nEnd1,
|
|
|
|
int nStt2, int nEnd2 );
|
|
|
|
|
|
|
|
public:
|
|
|
|
LgstCommonSubseq( ArrayComparator &rComparator );
|
|
|
|
~LgstCommonSubseq();
|
|
|
|
|
|
|
|
int Find( int *pSubseq1, int *pSubseq2 );
|
|
|
|
};
|
|
|
|
|
|
|
|
// Find a common subsequence in linear time
|
|
|
|
class FastCommonSubseq: private CommonSubseq
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
static const int CUTOFF = 2056;
|
|
|
|
|
|
|
|
int FindFastCS( int *pSeq1, int *pSeq2, int nStt1, int nEnd1,
|
|
|
|
int nStt2, int nEnd2 );
|
|
|
|
|
|
|
|
public:
|
|
|
|
FastCommonSubseq( ArrayComparator &rComparator )
|
|
|
|
: CommonSubseq( rComparator, CUTOFF )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
int Find( int *pSubseq1, int *pSubseq2 )
|
|
|
|
{
|
|
|
|
return FindFastCS( pSubseq1, pSubseq2, 0, rCmp.GetLen1(),
|
|
|
|
0, rCmp.GetLen2() );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
CompareLine::~CompareLine() {}
|
|
|
|
|
|
|
|
CompareData::CompareData()
|
2004-06-16 08:35:56 +00:00
|
|
|
: pIndex( 0 ), pChangedFlag( 0 ), nSttLineNum( 0 )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CompareData::~CompareData()
|
|
|
|
{
|
2002-05-13 11:14:05 +00:00
|
|
|
delete[] pIndex;
|
|
|
|
delete[] pChangedFlag;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
|
2010-12-12 08:04:28 -08:00
|
|
|
void CompareData::SetIndex( size_t nLine, size_t nIndex )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
if( !pIndex )
|
|
|
|
{
|
2010-12-12 08:04:28 -08:00
|
|
|
pIndex = new size_t[ aLines.size() ];
|
|
|
|
memset( pIndex, 0, aLines.size() * sizeof( size_t ) );
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
2010-12-12 08:04:28 -08:00
|
|
|
if( nLine < aLines.size() )
|
2000-09-18 23:08:29 +00:00
|
|
|
pIndex[ nLine ] = nIndex;
|
|
|
|
}
|
|
|
|
|
2010-12-12 08:04:28 -08:00
|
|
|
void CompareData::SetChanged( size_t nLine, bool bFlag )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
if( !pChangedFlag )
|
|
|
|
{
|
2010-12-12 08:04:28 -08:00
|
|
|
pChangedFlag = new bool[ aLines.size() +1 ];
|
|
|
|
memset( pChangedFlag, 0, (aLines.size() +1) * sizeof( bool ) );
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
2010-12-12 08:04:28 -08:00
|
|
|
if( nLine < aLines.size() )
|
2000-09-18 23:08:29 +00:00
|
|
|
pChangedFlag[ nLine ] = bFlag;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CompareData::CompareLines( CompareData& rData )
|
|
|
|
{
|
|
|
|
CheckRanges( rData );
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nDifferent;
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
Hash aH( GetLineCount() + rData.GetLineCount() + 1 );
|
|
|
|
aH.CalcHashValue( *this );
|
|
|
|
aH.CalcHashValue( rData );
|
|
|
|
nDifferent = aH.GetCount();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
Compare aComp( nDifferent, *this, rData );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong CompareData::ShowDiffs( const CompareData& rData )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nLen1 = rData.GetLineCount(), nLen2 = GetLineCount();
|
|
|
|
sal_uLong nStt1 = 0, nStt2 = 0;
|
|
|
|
sal_uLong nCnt = 0;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
while( nStt1 < nLen1 || nStt2 < nLen2 )
|
|
|
|
{
|
|
|
|
if( rData.GetChanged( nStt1 ) || GetChanged( nStt2 ) )
|
|
|
|
{
|
2011-12-22 17:27:32 +01:00
|
|
|
// Find a region of different lines between two pairs of identical
|
|
|
|
// lines.
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nSav1 = nStt1, nSav2 = nStt2;
|
2000-09-18 23:08:29 +00:00
|
|
|
while( nStt1 < nLen1 && rData.GetChanged( nStt1 )) ++nStt1;
|
|
|
|
while( nStt2 < nLen2 && GetChanged( nStt2 )) ++nStt2;
|
|
|
|
|
2011-12-22 17:27:32 +01:00
|
|
|
// Check if there are changed lines (only slightly different) and
|
|
|
|
// compare them in detail.
|
|
|
|
CheckForChangesInLine( rData, nSav1, nStt1, nSav2, nStt2 );
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
++nCnt;
|
|
|
|
}
|
|
|
|
++nStt1, ++nStt2;
|
|
|
|
}
|
|
|
|
return nCnt;
|
|
|
|
}
|
|
|
|
|
2012-10-20 23:12:12 +09:00
|
|
|
bool CompareData::HasDiffs( const CompareData& rData ) const
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2012-10-20 23:12:12 +09:00
|
|
|
bool bRet = false;
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nLen1 = rData.GetLineCount(), nLen2 = GetLineCount();
|
|
|
|
sal_uLong nStt1 = 0, nStt2 = 0;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
while( nStt1 < nLen1 || nStt2 < nLen2 )
|
|
|
|
{
|
|
|
|
if( rData.GetChanged( nStt1 ) || GetChanged( nStt2 ) )
|
|
|
|
{
|
2012-10-20 23:12:12 +09:00
|
|
|
bRet = true;
|
2000-09-18 23:08:29 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
++nStt1, ++nStt2;
|
|
|
|
}
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
void CompareData::ShowInsert( sal_uLong, sal_uLong )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
void CompareData::ShowDelete( const CompareData&, sal_uLong, sal_uLong, sal_uLong )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void CompareData::CheckForChangesInLine( const CompareData& ,
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong&, sal_uLong&, sal_uLong&, sal_uLong& )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
Hash::Hash( sal_uLong nSize )
|
2000-09-18 23:08:29 +00:00
|
|
|
: nCount( 1 )
|
|
|
|
{
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
static const sal_uLong primes[] =
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
509,
|
|
|
|
1021,
|
|
|
|
2039,
|
|
|
|
4093,
|
|
|
|
8191,
|
|
|
|
16381,
|
|
|
|
32749,
|
|
|
|
65521,
|
|
|
|
131071,
|
|
|
|
262139,
|
|
|
|
524287,
|
|
|
|
1048573,
|
|
|
|
2097143,
|
|
|
|
4194301,
|
|
|
|
8388593,
|
|
|
|
16777213,
|
|
|
|
33554393,
|
|
|
|
67108859, /* Preposterously large . . . */
|
|
|
|
134217689,
|
|
|
|
268435399,
|
|
|
|
536870909,
|
|
|
|
1073741789,
|
|
|
|
2147483647,
|
|
|
|
0
|
|
|
|
};
|
2003-12-01 15:33:57 +00:00
|
|
|
int i;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
pDataArr = new _HashData[ nSize ];
|
|
|
|
pDataArr[0].nNext = 0;
|
|
|
|
pDataArr[0].nHash = 0,
|
|
|
|
pDataArr[0].pLine = 0;
|
|
|
|
|
2003-12-01 15:33:57 +00:00
|
|
|
for( i = 0; primes[i] < nSize / 3; i++)
|
2000-09-18 23:08:29 +00:00
|
|
|
if( !primes[i] )
|
|
|
|
{
|
|
|
|
pHashArr = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
nPrime = primes[ i ];
|
2011-01-17 15:06:54 +01:00
|
|
|
pHashArr = new sal_uLong[ nPrime ];
|
|
|
|
memset( pHashArr, 0, nPrime * sizeof( sal_uLong ) );
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Hash::~Hash()
|
|
|
|
{
|
2002-05-13 11:14:05 +00:00
|
|
|
delete[] pHashArr;
|
|
|
|
delete[] pDataArr;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Hash::CalcHashValue( CompareData& rData )
|
|
|
|
{
|
|
|
|
if( pHashArr )
|
|
|
|
{
|
2010-12-13 05:50:06 -08:00
|
|
|
for( size_t n = 0; n < rData.GetLineCount(); ++n )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
const CompareLine* pLine = rData.GetLine( n );
|
2010-11-25 17:08:45 +01:00
|
|
|
OSL_ENSURE( pLine, "wo ist die Line?" );
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nH = pLine->GetHashValue();
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong* pFound = &pHashArr[ nH % nPrime ];
|
2010-12-13 05:50:06 -08:00
|
|
|
size_t i;
|
2003-12-01 15:33:57 +00:00
|
|
|
for( i = *pFound; ; i = pDataArr[i].nNext )
|
2000-09-18 23:08:29 +00:00
|
|
|
if( !i )
|
|
|
|
{
|
|
|
|
i = nCount++;
|
|
|
|
pDataArr[i].nNext = *pFound;
|
|
|
|
pDataArr[i].nHash = nH;
|
|
|
|
pDataArr[i].pLine = pLine;
|
|
|
|
*pFound = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if( pDataArr[i].nHash == nH &&
|
|
|
|
pDataArr[i].pLine->Compare( *pLine ))
|
|
|
|
break;
|
|
|
|
|
|
|
|
rData.SetIndex( n, i );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
Compare::Compare( sal_uLong nDiff, CompareData& rData1, CompareData& rData2 )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
MovedData *pMD1, *pMD2;
|
2011-11-04 14:46:42 +01:00
|
|
|
// Look for the differing lines
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
sal_Char* pDiscard1 = new sal_Char[ rData1.GetLineCount() ];
|
|
|
|
sal_Char* pDiscard2 = new sal_Char[ rData2.GetLineCount() ];
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong* pCount1 = new sal_uLong[ nDiff ];
|
|
|
|
sal_uLong* pCount2 = new sal_uLong[ nDiff ];
|
|
|
|
memset( pCount1, 0, nDiff * sizeof( sal_uLong ));
|
|
|
|
memset( pCount2, 0, nDiff * sizeof( sal_uLong ));
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// find indices in CompareData which have been assigned multiple times
|
2000-09-18 23:08:29 +00:00
|
|
|
CountDifference( rData1, pCount1 );
|
|
|
|
CountDifference( rData2, pCount2 );
|
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// All which occur only once now have either been inserted or deleted.
|
|
|
|
// All which are also contained in the other one have been moved.
|
2000-09-18 23:08:29 +00:00
|
|
|
SetDiscard( rData1, pDiscard1, pCount2 );
|
|
|
|
SetDiscard( rData2, pDiscard2, pCount1 );
|
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// forget the arrays again
|
2009-11-06 11:03:40 +00:00
|
|
|
delete [] pCount1; delete [] pCount2;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
CheckDiscard( rData1.GetLineCount(), pDiscard1 );
|
|
|
|
CheckDiscard( rData2.GetLineCount(), pDiscard2 );
|
|
|
|
|
|
|
|
pMD1 = new MovedData( rData1, pDiscard1 );
|
|
|
|
pMD2 = new MovedData( rData2, pDiscard2 );
|
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// forget the arrays again
|
2009-11-06 11:03:40 +00:00
|
|
|
delete [] pDiscard1; delete [] pDiscard2;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
CompareSequence aTmp( rData1, rData2, *pMD1, *pMD2 );
|
|
|
|
}
|
|
|
|
|
|
|
|
ShiftBoundaries( rData1, rData2 );
|
|
|
|
|
|
|
|
delete pMD1;
|
|
|
|
delete pMD2;
|
|
|
|
}
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
void Compare::CountDifference( const CompareData& rData, sal_uLong* pCounts )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nLen = rData.GetLineCount();
|
|
|
|
for( sal_uLong n = 0; n < nLen; ++n )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nIdx = rData.GetIndex( n );
|
2000-09-18 23:08:29 +00:00
|
|
|
++pCounts[ nIdx ];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Compare::SetDiscard( const CompareData& rData,
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_Char* pDiscard, sal_uLong* pCounts )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nLen = rData.GetLineCount();
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// calculate Max with respect to the line count
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uInt16 nMax = 5;
|
|
|
|
sal_uLong n;
|
2003-12-01 15:33:57 +00:00
|
|
|
|
|
|
|
for( n = nLen / 64; ( n = n >> 2 ) > 0; )
|
2000-09-18 23:08:29 +00:00
|
|
|
nMax <<= 1;
|
|
|
|
|
|
|
|
for( n = 0; n < nLen; ++n )
|
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nIdx = rData.GetIndex( n );
|
2000-09-18 23:08:29 +00:00
|
|
|
if( nIdx )
|
|
|
|
{
|
|
|
|
nIdx = pCounts[ nIdx ];
|
|
|
|
pDiscard[ n ] = !nIdx ? 1 : nIdx > nMax ? 2 : 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pDiscard[ n ] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
void Compare::CheckDiscard( sal_uLong nLen, sal_Char* pDiscard )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
for( sal_uLong n = 0; n < nLen; ++n )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
if( 2 == pDiscard[ n ] )
|
|
|
|
pDiscard[n] = 0;
|
|
|
|
else if( pDiscard[ n ] )
|
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong j;
|
|
|
|
sal_uLong length;
|
|
|
|
sal_uLong provisional = 0;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
/* Find end of this run of discardable lines.
|
|
|
|
Count how many are provisionally discardable. */
|
|
|
|
for (j = n; j < nLen; j++)
|
|
|
|
{
|
|
|
|
if( !pDiscard[j] )
|
|
|
|
break;
|
|
|
|
if( 2 == pDiscard[j] )
|
|
|
|
++provisional;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Cancel provisional discards at end, and shrink the run. */
|
|
|
|
while( j > n && 2 == pDiscard[j - 1] )
|
|
|
|
pDiscard[ --j ] = 0, --provisional;
|
|
|
|
|
|
|
|
/* Now we have the length of a run of discardable lines
|
|
|
|
whose first and last are not provisional. */
|
|
|
|
length = j - n;
|
|
|
|
|
|
|
|
/* If 1/4 of the lines in the run are provisional,
|
|
|
|
cancel discarding of all provisional lines in the run. */
|
|
|
|
if (provisional * 4 > length)
|
|
|
|
{
|
|
|
|
while (j > n)
|
|
|
|
if (pDiscard[--j] == 2)
|
|
|
|
pDiscard[j] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong consec;
|
|
|
|
sal_uLong minimum = 1;
|
|
|
|
sal_uLong tem = length / 4;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
/* MINIMUM is approximate square root of LENGTH/4.
|
|
|
|
A subrun of two or more provisionals can stand
|
|
|
|
when LENGTH is at least 16.
|
|
|
|
A subrun of 4 or more can stand when LENGTH >= 64. */
|
|
|
|
while ((tem = tem >> 2) > 0)
|
|
|
|
minimum *= 2;
|
|
|
|
minimum++;
|
|
|
|
|
|
|
|
/* Cancel any subrun of MINIMUM or more provisionals
|
|
|
|
within the larger run. */
|
|
|
|
for (j = 0, consec = 0; j < length; j++)
|
|
|
|
if (pDiscard[n + j] != 2)
|
|
|
|
consec = 0;
|
|
|
|
else if (minimum == ++consec)
|
|
|
|
/* Back up to start of subrun, to cancel it all. */
|
|
|
|
j -= consec;
|
|
|
|
else if (minimum < consec)
|
|
|
|
pDiscard[n + j] = 0;
|
|
|
|
|
|
|
|
/* Scan from beginning of run
|
|
|
|
until we find 3 or more nonprovisionals in a row
|
|
|
|
or until the first nonprovisional at least 8 lines in.
|
|
|
|
Until that point, cancel any provisionals. */
|
|
|
|
for (j = 0, consec = 0; j < length; j++)
|
|
|
|
{
|
|
|
|
if (j >= 8 && pDiscard[n + j] == 1)
|
|
|
|
break;
|
|
|
|
if (pDiscard[n + j] == 2)
|
|
|
|
consec = 0, pDiscard[n + j] = 0;
|
|
|
|
else if (pDiscard[n + j] == 0)
|
|
|
|
consec = 0;
|
|
|
|
else
|
|
|
|
consec++;
|
|
|
|
if (consec == 3)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* I advances to the last line of the run. */
|
|
|
|
n += length - 1;
|
|
|
|
|
|
|
|
/* Same thing, from end. */
|
|
|
|
for (j = 0, consec = 0; j < length; j++)
|
|
|
|
{
|
|
|
|
if (j >= 8 && pDiscard[n - j] == 1)
|
|
|
|
break;
|
|
|
|
if (pDiscard[n - j] == 2)
|
|
|
|
consec = 0, pDiscard[n - j] = 0;
|
|
|
|
else if (pDiscard[n - j] == 0)
|
|
|
|
consec = 0;
|
|
|
|
else
|
|
|
|
consec++;
|
|
|
|
if (consec == 3)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Compare::MovedData::MovedData( CompareData& rData, sal_Char* pDiscard )
|
|
|
|
: pIndex( 0 ), pLineNum( 0 ), nCount( 0 )
|
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nLen = rData.GetLineCount();
|
|
|
|
sal_uLong n;
|
2003-12-01 15:33:57 +00:00
|
|
|
|
|
|
|
for( n = 0; n < nLen; ++n )
|
2000-09-18 23:08:29 +00:00
|
|
|
if( pDiscard[ n ] )
|
|
|
|
rData.SetChanged( n );
|
|
|
|
else
|
|
|
|
++nCount;
|
|
|
|
|
|
|
|
if( nCount )
|
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
pIndex = new sal_uLong[ nCount ];
|
|
|
|
pLineNum = new sal_uLong[ nCount ];
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
for( n = 0, nCount = 0; n < nLen; ++n )
|
|
|
|
if( !pDiscard[ n ] )
|
|
|
|
{
|
|
|
|
pIndex[ nCount ] = rData.GetIndex( n );
|
|
|
|
pLineNum[ nCount++ ] = n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Compare::MovedData::~MovedData()
|
|
|
|
{
|
2011-05-13 17:28:08 +02:00
|
|
|
delete [] pIndex;
|
|
|
|
delete [] pLineNum;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// Find the differing lines
|
2000-09-18 23:08:29 +00:00
|
|
|
Compare::CompareSequence::CompareSequence(
|
|
|
|
CompareData& rD1, CompareData& rD2,
|
|
|
|
const MovedData& rMD1, const MovedData& rMD2 )
|
|
|
|
: rData1( rD1 ), rData2( rD2 ), rMoved1( rMD1 ), rMoved2( rMD2 )
|
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nSize = rMD1.GetCount() + rMD2.GetCount() + 3;
|
2000-09-18 23:08:29 +00:00
|
|
|
pMemory = new long[ nSize * 2 ];
|
|
|
|
pFDiag = pMemory + ( rMD2.GetCount() + 1 );
|
|
|
|
pBDiag = pMemory + ( nSize + rMD2.GetCount() + 1 );
|
|
|
|
|
|
|
|
Compare( 0, rMD1.GetCount(), 0, rMD2.GetCount() );
|
|
|
|
}
|
|
|
|
|
|
|
|
Compare::CompareSequence::~CompareSequence()
|
|
|
|
{
|
2011-05-13 17:28:08 +02:00
|
|
|
delete [] pMemory;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
void Compare::CompareSequence::Compare( sal_uLong nStt1, sal_uLong nEnd1,
|
|
|
|
sal_uLong nStt2, sal_uLong nEnd2 )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
/* Slide down the bottom initial diagonal. */
|
|
|
|
while( nStt1 < nEnd1 && nStt2 < nEnd2 &&
|
|
|
|
rMoved1.GetIndex( nStt1 ) == rMoved2.GetIndex( nStt2 ))
|
|
|
|
++nStt1, ++nStt2;
|
|
|
|
|
|
|
|
/* Slide up the top initial diagonal. */
|
|
|
|
while( nEnd1 > nStt1 && nEnd2 > nStt2 &&
|
|
|
|
rMoved1.GetIndex( nEnd1 - 1 ) == rMoved2.GetIndex( nEnd2 - 1 ))
|
|
|
|
--nEnd1, --nEnd2;
|
|
|
|
|
|
|
|
/* Handle simple cases. */
|
|
|
|
if( nStt1 == nEnd1 )
|
|
|
|
while( nStt2 < nEnd2 )
|
|
|
|
rData2.SetChanged( rMoved2.GetLineNum( nStt2++ ));
|
|
|
|
|
|
|
|
else if (nStt2 == nEnd2)
|
|
|
|
while (nStt1 < nEnd1)
|
|
|
|
rData1.SetChanged( rMoved1.GetLineNum( nStt1++ ));
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong c, d, b;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
/* Find a point of correspondence in the middle of the files. */
|
|
|
|
|
|
|
|
d = CheckDiag( nStt1, nEnd1, nStt2, nEnd2, &c );
|
|
|
|
b = pBDiag[ d ];
|
|
|
|
|
|
|
|
if( 1 != c )
|
|
|
|
{
|
|
|
|
/* Use that point to split this problem into two subproblems. */
|
|
|
|
Compare( nStt1, b, nStt2, b - d );
|
|
|
|
/* This used to use f instead of b,
|
|
|
|
but that is incorrect!
|
|
|
|
It is not necessarily the case that diagonal d
|
|
|
|
has a snake from b to f. */
|
|
|
|
Compare( b, nEnd1, b - d, nEnd2 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong Compare::CompareSequence::CheckDiag( sal_uLong nStt1, sal_uLong nEnd1,
|
|
|
|
sal_uLong nStt2, sal_uLong nEnd2, sal_uLong* pCost )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
const long dmin = nStt1 - nEnd2; /* Minimum valid diagonal. */
|
|
|
|
const long dmax = nEnd1 - nStt2; /* Maximum valid diagonal. */
|
|
|
|
const long fmid = nStt1 - nStt2; /* Center diagonal of top-down search. */
|
|
|
|
const long bmid = nEnd1 - nEnd2; /* Center diagonal of bottom-up search. */
|
|
|
|
|
|
|
|
long fmin = fmid, fmax = fmid; /* Limits of top-down search. */
|
|
|
|
long bmin = bmid, bmax = bmid; /* Limits of bottom-up search. */
|
|
|
|
|
|
|
|
long c; /* Cost. */
|
|
|
|
long odd = (fmid - bmid) & 1; /* True if southeast corner is on an odd
|
|
|
|
diagonal with respect to the northwest. */
|
|
|
|
|
|
|
|
pFDiag[fmid] = nStt1;
|
|
|
|
pBDiag[bmid] = nEnd1;
|
|
|
|
|
|
|
|
for (c = 1;; ++c)
|
|
|
|
{
|
|
|
|
long d; /* Active diagonal. */
|
|
|
|
|
|
|
|
/* Extend the top-down search by an edit step in each diagonal. */
|
|
|
|
fmin > dmin ? pFDiag[--fmin - 1] = -1 : ++fmin;
|
|
|
|
fmax < dmax ? pFDiag[++fmax + 1] = -1 : --fmax;
|
|
|
|
for (d = fmax; d >= fmin; d -= 2)
|
|
|
|
{
|
2011-01-27 12:09:39 +00:00
|
|
|
long x, y, tlo = pFDiag[d - 1], thi = pFDiag[d + 1];
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
if (tlo >= thi)
|
|
|
|
x = tlo + 1;
|
|
|
|
else
|
|
|
|
x = thi;
|
|
|
|
y = x - d;
|
2011-01-17 15:06:54 +01:00
|
|
|
while( sal_uLong(x) < nEnd1 && sal_uLong(y) < nEnd2 &&
|
2000-09-18 23:08:29 +00:00
|
|
|
rMoved1.GetIndex( x ) == rMoved2.GetIndex( y ))
|
|
|
|
++x, ++y;
|
|
|
|
pFDiag[d] = x;
|
|
|
|
if( odd && bmin <= d && d <= bmax && pBDiag[d] <= pFDiag[d] )
|
|
|
|
{
|
|
|
|
*pCost = 2 * c - 1;
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Similar extend the bottom-up search. */
|
|
|
|
bmin > dmin ? pBDiag[--bmin - 1] = INT_MAX : ++bmin;
|
|
|
|
bmax < dmax ? pBDiag[++bmax + 1] = INT_MAX : --bmax;
|
|
|
|
for (d = bmax; d >= bmin; d -= 2)
|
|
|
|
{
|
2011-01-27 12:09:39 +00:00
|
|
|
long x, y, tlo = pBDiag[d - 1], thi = pBDiag[d + 1];
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
if (tlo < thi)
|
|
|
|
x = tlo;
|
|
|
|
else
|
|
|
|
x = thi - 1;
|
|
|
|
y = x - d;
|
2011-01-17 15:06:54 +01:00
|
|
|
while( sal_uLong(x) > nStt1 && sal_uLong(y) > nStt2 &&
|
2000-09-18 23:08:29 +00:00
|
|
|
rMoved1.GetIndex( x - 1 ) == rMoved2.GetIndex( y - 1 ))
|
|
|
|
--x, --y;
|
|
|
|
pBDiag[d] = x;
|
|
|
|
if (!odd && fmin <= d && d <= fmax && pBDiag[d] <= pFDiag[d])
|
|
|
|
{
|
|
|
|
*pCost = 2 * c;
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Compare::ShiftBoundaries( CompareData& rData1, CompareData& rData2 )
|
|
|
|
{
|
2003-10-06 18:01:12 +00:00
|
|
|
for( int iz = 0; iz < 2; ++iz )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
CompareData* pData = &rData1;
|
|
|
|
CompareData* pOtherData = &rData2;
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong i = 0;
|
|
|
|
sal_uLong j = 0;
|
|
|
|
sal_uLong i_end = pData->GetLineCount();
|
|
|
|
sal_uLong preceding = ULONG_MAX;
|
|
|
|
sal_uLong other_preceding = ULONG_MAX;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong start, other_start;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
/* Scan forwards to find beginning of another run of changes.
|
|
|
|
Also keep track of the corresponding point in the other file. */
|
|
|
|
|
|
|
|
while( i < i_end && !pData->GetChanged( i ) )
|
|
|
|
{
|
|
|
|
while( pOtherData->GetChanged( j++ ))
|
|
|
|
/* Non-corresponding lines in the other file
|
|
|
|
will count as the preceding batch of changes. */
|
|
|
|
other_preceding = j;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == i_end)
|
|
|
|
break;
|
|
|
|
|
|
|
|
start = i;
|
|
|
|
other_start = j;
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
/* Now find the end of this run of changes. */
|
|
|
|
|
|
|
|
while( pData->GetChanged( ++i ))
|
|
|
|
;
|
|
|
|
|
|
|
|
/* If the first changed line matches the following unchanged one,
|
|
|
|
and this run does not follow right after a previous run,
|
|
|
|
and there are no lines deleted from the other file here,
|
|
|
|
then classify the first changed line as unchanged
|
|
|
|
and the following line as changed in its place. */
|
|
|
|
|
|
|
|
/* You might ask, how could this run follow right after another?
|
|
|
|
Only because the previous run was shifted here. */
|
|
|
|
|
|
|
|
if( i != i_end &&
|
|
|
|
pData->GetIndex( start ) == pData->GetIndex( i ) &&
|
|
|
|
!pOtherData->GetChanged( j ) &&
|
|
|
|
!( start == preceding || other_start == other_preceding ))
|
|
|
|
{
|
|
|
|
pData->SetChanged( start++, 0 );
|
|
|
|
pData->SetChanged( i );
|
|
|
|
/* Since one line-that-matches is now before this run
|
|
|
|
instead of after, we must advance in the other file
|
|
|
|
to keep in synch. */
|
|
|
|
++j;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
preceding = i;
|
|
|
|
other_preceding = j;
|
|
|
|
}
|
|
|
|
|
|
|
|
pData = &rData2;
|
|
|
|
pOtherData = &rData1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class SwCompareLine : public CompareLine
|
|
|
|
{
|
|
|
|
const SwNode& rNode;
|
|
|
|
public:
|
|
|
|
SwCompareLine( const SwNode& rNd );
|
|
|
|
virtual ~SwCompareLine();
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
virtual sal_uLong GetHashValue() const;
|
2012-10-20 23:12:12 +09:00
|
|
|
virtual bool Compare( const CompareLine& rLine ) const;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
static sal_uLong GetTxtNodeHashValue( const SwTxtNode& rNd, sal_uLong nVal );
|
2012-10-20 23:12:12 +09:00
|
|
|
static bool CompareNode( const SwNode& rDstNd, const SwNode& rSrcNd );
|
|
|
|
static bool CompareTxtNd( const SwTxtNode& rDstNd,
|
2000-09-18 23:08:29 +00:00
|
|
|
const SwTxtNode& rSrcNd );
|
|
|
|
|
2012-10-20 23:12:12 +09:00
|
|
|
bool ChangesInLine( const SwCompareLine& rLine,
|
2000-09-18 23:08:29 +00:00
|
|
|
SwPaM *& rpInsRing, SwPaM*& rpDelRing ) const;
|
|
|
|
|
|
|
|
const SwNode& GetNode() const { return rNode; }
|
|
|
|
|
|
|
|
const SwNode& GetEndNode() const;
|
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// for debugging
|
2000-09-18 23:08:29 +00:00
|
|
|
String GetText() const;
|
|
|
|
};
|
|
|
|
|
|
|
|
class SwCompareData : public CompareData
|
|
|
|
{
|
|
|
|
SwDoc& rDoc;
|
|
|
|
SwPaM *pInsRing, *pDelRing;
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong PrevIdx( const SwNode* pNd );
|
|
|
|
sal_uLong NextIdx( const SwNode* pNd );
|
2001-09-27 12:42:58 +00:00
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
virtual void CheckRanges( CompareData& );
|
2011-01-17 15:06:54 +01:00
|
|
|
virtual void ShowInsert( sal_uLong nStt, sal_uLong nEnd );
|
|
|
|
virtual void ShowDelete( const CompareData& rData, sal_uLong nStt,
|
|
|
|
sal_uLong nEnd, sal_uLong nInsPos );
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
virtual void CheckForChangesInLine( const CompareData& rData,
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong& nStt, sal_uLong& nEnd,
|
|
|
|
sal_uLong& nThisStt, sal_uLong& nThisEnd );
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
SwCompareData( SwDoc& rD ) : rDoc( rD ), pInsRing(0), pDelRing(0) {}
|
|
|
|
virtual ~SwCompareData();
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
void SetRedlinesToDoc( sal_Bool bUseDocInfo );
|
2000-09-18 23:08:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
SwCompareLine::SwCompareLine( const SwNode& rNd )
|
|
|
|
: rNode( rNd )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
SwCompareLine::~SwCompareLine()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong SwCompareLine::GetHashValue() const
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nRet = 0;
|
2000-09-18 23:08:29 +00:00
|
|
|
switch( rNode.GetNodeType() )
|
|
|
|
{
|
|
|
|
case ND_TEXTNODE:
|
|
|
|
nRet = GetTxtNodeHashValue( (SwTxtNode&)rNode, nRet );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ND_TABLENODE:
|
|
|
|
{
|
|
|
|
const SwNode* pEndNd = rNode.EndOfSectionNode();
|
|
|
|
SwNodeIndex aIdx( rNode );
|
|
|
|
while( &aIdx.GetNode() != pEndNd )
|
|
|
|
{
|
|
|
|
if( aIdx.GetNode().IsTxtNode() )
|
|
|
|
nRet = GetTxtNodeHashValue( (SwTxtNode&)aIdx.GetNode(), nRet );
|
2012-10-15 23:31:02 +02:00
|
|
|
++aIdx;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ND_SECTIONNODE:
|
2001-09-27 12:42:58 +00:00
|
|
|
{
|
|
|
|
String sStr( GetText() );
|
|
|
|
for( xub_StrLen n = 0; n < sStr.Len(); ++n )
|
|
|
|
( nRet <<= 1 ) += sStr.GetChar( n );
|
|
|
|
}
|
2000-09-18 23:08:29 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ND_GRFNODE:
|
|
|
|
case ND_OLENODE:
|
2011-11-04 14:46:42 +01:00
|
|
|
// Fixed ID? Should never occur ...
|
2000-09-18 23:08:29 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return nRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
const SwNode& SwCompareLine::GetEndNode() const
|
|
|
|
{
|
|
|
|
const SwNode* pNd = &rNode;
|
|
|
|
switch( rNode.GetNodeType() )
|
|
|
|
{
|
|
|
|
case ND_TABLENODE:
|
|
|
|
pNd = rNode.EndOfSectionNode();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ND_SECTIONNODE:
|
2001-09-27 12:42:58 +00:00
|
|
|
{
|
|
|
|
const SwSectionNode& rSNd = (SwSectionNode&)rNode;
|
|
|
|
const SwSection& rSect = rSNd.GetSection();
|
|
|
|
if( CONTENT_SECTION != rSect.GetType() || rSect.IsProtect() )
|
|
|
|
pNd = rNode.EndOfSectionNode();
|
|
|
|
}
|
2000-09-18 23:08:29 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return *pNd;
|
|
|
|
}
|
|
|
|
|
2012-10-20 23:12:12 +09:00
|
|
|
bool SwCompareLine::Compare( const CompareLine& rLine ) const
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
return CompareNode( rNode, ((SwCompareLine&)rLine).rNode );
|
|
|
|
}
|
|
|
|
|
2010-01-13 13:03:53 +01:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
static String SimpleTableToText(const SwNode &rNode)
|
|
|
|
{
|
|
|
|
String sRet;
|
|
|
|
const SwNode* pEndNd = rNode.EndOfSectionNode();
|
|
|
|
SwNodeIndex aIdx( rNode );
|
|
|
|
while (&aIdx.GetNode() != pEndNd)
|
|
|
|
{
|
|
|
|
if (aIdx.GetNode().IsTxtNode())
|
|
|
|
{
|
|
|
|
if (sRet.Len())
|
|
|
|
{
|
|
|
|
sRet.Append( '\n' );
|
|
|
|
}
|
|
|
|
sRet.Append( aIdx.GetNode().GetTxtNode()->GetExpandTxt() );
|
|
|
|
}
|
2012-10-15 23:31:02 +02:00
|
|
|
++aIdx;
|
2010-01-13 13:03:53 +01:00
|
|
|
}
|
|
|
|
return sRet;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-20 23:12:12 +09:00
|
|
|
bool SwCompareLine::CompareNode( const SwNode& rDstNd, const SwNode& rSrcNd )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2007-05-25 12:00:37 +00:00
|
|
|
if( rSrcNd.GetNodeType() != rDstNd.GetNodeType() )
|
2012-10-20 23:12:12 +09:00
|
|
|
return false;
|
2007-05-25 12:00:37 +00:00
|
|
|
|
2012-10-20 23:12:12 +09:00
|
|
|
bool bRet = false;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2007-05-25 12:00:37 +00:00
|
|
|
switch( rDstNd.GetNodeType() )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2007-05-25 12:00:37 +00:00
|
|
|
case ND_TEXTNODE:
|
2011-12-22 17:27:32 +01:00
|
|
|
bRet = CompareTxtNd( (SwTxtNode&)rDstNd, (SwTxtNode&)rSrcNd )
|
|
|
|
&& ( !CmpOptions.bUseRsid || ((SwTxtNode&)rDstNd).CompareParRsid( (SwTxtNode&)rSrcNd ) );
|
2000-09-18 23:08:29 +00:00
|
|
|
break;
|
|
|
|
|
2007-05-25 12:00:37 +00:00
|
|
|
case ND_TABLENODE:
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
const SwTableNode& rTSrcNd = (SwTableNode&)rSrcNd;
|
|
|
|
const SwTableNode& rTDstNd = (SwTableNode&)rDstNd;
|
|
|
|
|
|
|
|
bRet = ( rTSrcNd.EndOfSectionIndex() - rTSrcNd.GetIndex() ) ==
|
|
|
|
( rTDstNd.EndOfSectionIndex() - rTDstNd.GetIndex() );
|
2010-01-13 13:03:53 +01:00
|
|
|
|
|
|
|
// --> #i107826#: compare actual table content
|
|
|
|
if (bRet)
|
|
|
|
{
|
|
|
|
bRet = (SimpleTableToText(rSrcNd) == SimpleTableToText(rDstNd));
|
|
|
|
}
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2007-05-25 12:00:37 +00:00
|
|
|
case ND_SECTIONNODE:
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2001-09-27 12:42:58 +00:00
|
|
|
const SwSectionNode& rSSrcNd = (SwSectionNode&)rSrcNd,
|
|
|
|
& rSDstNd = (SwSectionNode&)rDstNd;
|
|
|
|
const SwSection& rSrcSect = rSSrcNd.GetSection(),
|
|
|
|
& rDstSect = rSDstNd.GetSection();
|
|
|
|
SectionType eSrcSectType = rSrcSect.GetType(),
|
|
|
|
eDstSectType = rDstSect.GetType();
|
|
|
|
switch( eSrcSectType )
|
|
|
|
{
|
|
|
|
case CONTENT_SECTION:
|
|
|
|
bRet = CONTENT_SECTION == eDstSectType &&
|
|
|
|
rSrcSect.IsProtect() == rDstSect.IsProtect();
|
|
|
|
if( bRet && rSrcSect.IsProtect() )
|
|
|
|
{
|
|
|
|
// the only have they both the same size
|
|
|
|
bRet = ( rSSrcNd.EndOfSectionIndex() - rSSrcNd.GetIndex() ) ==
|
|
|
|
( rSDstNd.EndOfSectionIndex() - rSDstNd.GetIndex() );
|
|
|
|
}
|
|
|
|
break;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2001-09-27 12:42:58 +00:00
|
|
|
case TOX_HEADER_SECTION:
|
|
|
|
case TOX_CONTENT_SECTION:
|
|
|
|
if( TOX_HEADER_SECTION == eDstSectType ||
|
|
|
|
TOX_CONTENT_SECTION == eDstSectType )
|
|
|
|
{
|
|
|
|
// the same type of TOX?
|
|
|
|
const SwTOXBase* pSrcTOX = rSrcSect.GetTOXBase();
|
|
|
|
const SwTOXBase* pDstTOX = rDstSect.GetTOXBase();
|
|
|
|
bRet = pSrcTOX && pDstTOX
|
|
|
|
&& pSrcTOX->GetType() == pDstTOX->GetType()
|
|
|
|
&& pSrcTOX->GetTitle() == pDstTOX->GetTitle()
|
|
|
|
&& pSrcTOX->GetTypeName() == pDstTOX->GetTypeName()
|
|
|
|
// && pSrcTOX->GetTOXName() == pDstTOX->GetTOXName()
|
|
|
|
;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DDE_LINK_SECTION:
|
|
|
|
case FILE_LINK_SECTION:
|
|
|
|
bRet = eSrcSectType == eDstSectType &&
|
|
|
|
rSrcSect.GetLinkFileName() ==
|
|
|
|
rDstSect.GetLinkFileName();
|
|
|
|
break;
|
|
|
|
}
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2007-05-25 12:00:37 +00:00
|
|
|
case ND_ENDNODE:
|
|
|
|
bRet = rSrcNd.StartOfSectionNode()->GetNodeType() ==
|
|
|
|
rDstNd.StartOfSectionNode()->GetNodeType();
|
2010-01-13 13:03:53 +01:00
|
|
|
|
|
|
|
// --> #i107826#: compare actual table content
|
|
|
|
if (bRet && rSrcNd.StartOfSectionNode()->GetNodeType() == ND_TABLENODE)
|
|
|
|
{
|
|
|
|
bRet = CompareNode(
|
|
|
|
*rSrcNd.StartOfSectionNode(), *rDstNd.StartOfSectionNode());
|
|
|
|
}
|
|
|
|
|
2007-05-25 12:00:37 +00:00
|
|
|
break;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
String SwCompareLine::GetText() const
|
|
|
|
{
|
|
|
|
String sRet;
|
|
|
|
switch( rNode.GetNodeType() )
|
|
|
|
{
|
|
|
|
case ND_TEXTNODE:
|
|
|
|
sRet = ((SwTxtNode&)rNode).GetExpandTxt();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ND_TABLENODE:
|
|
|
|
{
|
2010-01-13 13:03:53 +01:00
|
|
|
sRet = SimpleTableToText(rNode);
|
2000-09-18 23:08:29 +00:00
|
|
|
sRet.InsertAscii( "Tabelle: ", 0 );
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ND_SECTIONNODE:
|
2001-09-27 12:42:58 +00:00
|
|
|
{
|
|
|
|
sRet.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "Section - Node:" ));
|
|
|
|
|
|
|
|
const SwSectionNode& rSNd = (SwSectionNode&)rNode;
|
|
|
|
const SwSection& rSect = rSNd.GetSection();
|
|
|
|
switch( rSect.GetType() )
|
|
|
|
{
|
|
|
|
case CONTENT_SECTION:
|
|
|
|
if( rSect.IsProtect() )
|
|
|
|
sRet.Append( String::CreateFromInt32(
|
|
|
|
rSNd.EndOfSectionIndex() - rSNd.GetIndex() ));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TOX_HEADER_SECTION:
|
|
|
|
case TOX_CONTENT_SECTION:
|
|
|
|
{
|
|
|
|
const SwTOXBase* pTOX = rSect.GetTOXBase();
|
|
|
|
if( pTOX )
|
|
|
|
sRet.Append( pTOX->GetTitle() )
|
|
|
|
.Append( pTOX->GetTypeName() )
|
|
|
|
// .Append( pTOX->GetTOXName() )
|
|
|
|
.Append( String::CreateFromInt32( pTOX->GetType() ));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DDE_LINK_SECTION:
|
|
|
|
case FILE_LINK_SECTION:
|
|
|
|
sRet += rSect.GetLinkFileName();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2000-09-18 23:08:29 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ND_GRFNODE:
|
|
|
|
sRet.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "Grafik - Node:" ));
|
|
|
|
break;
|
|
|
|
case ND_OLENODE:
|
|
|
|
sRet.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "OLE - Node:" ));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return sRet;
|
|
|
|
}
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong SwCompareLine::GetTxtNodeHashValue( const SwTxtNode& rNd, sal_uLong nVal )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
String sStr( rNd.GetExpandTxt() );
|
|
|
|
for( xub_StrLen n = 0; n < sStr.Len(); ++n )
|
|
|
|
( nVal <<= 1 ) += sStr.GetChar( n );
|
|
|
|
return nVal;
|
|
|
|
}
|
|
|
|
|
2012-10-20 23:12:12 +09:00
|
|
|
bool SwCompareLine::CompareTxtNd( const SwTxtNode& rDstNd,
|
2000-09-18 23:08:29 +00:00
|
|
|
const SwTxtNode& rSrcNd )
|
|
|
|
{
|
2012-10-20 23:12:12 +09:00
|
|
|
bool bRet = false;
|
2011-11-04 14:46:42 +01:00
|
|
|
// Very simple at first
|
2000-09-18 23:08:29 +00:00
|
|
|
if( rDstNd.GetTxt() == rSrcNd.GetTxt() )
|
|
|
|
{
|
2011-11-04 14:46:42 +01:00
|
|
|
// The text is the same, but are the "special attributes" (0xFF) also the same?
|
2012-10-20 23:12:12 +09:00
|
|
|
bRet = true;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
|
2012-10-20 23:12:12 +09:00
|
|
|
bool SwCompareLine::ChangesInLine( const SwCompareLine& rLine,
|
2000-09-18 23:08:29 +00:00
|
|
|
SwPaM *& rpInsRing, SwPaM*& rpDelRing ) const
|
|
|
|
{
|
2012-10-20 23:12:12 +09:00
|
|
|
bool bRet = false;
|
2011-12-22 17:27:32 +01:00
|
|
|
|
|
|
|
// Only compare textnodes
|
2000-09-18 23:08:29 +00:00
|
|
|
if( ND_TEXTNODE == rNode.GetNodeType() &&
|
|
|
|
ND_TEXTNODE == rLine.GetNode().GetNodeType() )
|
|
|
|
{
|
2011-12-22 17:27:32 +01:00
|
|
|
SwTxtNode& rDstNd = *(SwTxtNode*)rNode.GetTxtNode();
|
2000-09-18 23:08:29 +00:00
|
|
|
const SwTxtNode& rSrcNd = *rLine.GetNode().GetTxtNode();
|
2011-12-22 17:27:32 +01:00
|
|
|
SwDoc* pDstDoc = rDstNd.GetDoc();
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2011-12-22 17:27:32 +01:00
|
|
|
int nLcsLen = 0;
|
2003-12-01 15:33:57 +00:00
|
|
|
|
2011-12-22 17:27:32 +01:00
|
|
|
int nDstLen = rDstNd.GetTxt().Len();
|
|
|
|
int nSrcLen = rSrcNd.GetTxt().Len();
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2011-12-22 17:27:32 +01:00
|
|
|
int nMinLen = std::min( nDstLen , nSrcLen );
|
|
|
|
int nAvgLen = ( nDstLen + nSrcLen )/2;
|
|
|
|
|
|
|
|
int *pLcsDst = new int[ nMinLen + 1 ];
|
|
|
|
int *pLcsSrc = new int[ nMinLen + 1 ];
|
|
|
|
|
|
|
|
if( CmpOptions.eCmpMode == SVX_CMP_BY_WORD )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2011-12-22 17:27:32 +01:00
|
|
|
int *pTmpLcsDst = new int[ nMinLen + 1 ];
|
|
|
|
int *pTmpLcsSrc = new int[ nMinLen + 1 ];
|
|
|
|
|
|
|
|
WordArrayComparator aCmp( &rDstNd, &rSrcNd );
|
|
|
|
|
|
|
|
LgstCommonSubseq aSeq( aCmp );
|
|
|
|
|
|
|
|
nLcsLen = aSeq.Find( pTmpLcsDst, pTmpLcsSrc );
|
|
|
|
|
|
|
|
if( CmpOptions.nIgnoreLen )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2011-12-22 17:27:32 +01:00
|
|
|
nLcsLen = aSeq.IgnoreIsolatedPieces( pTmpLcsDst, pTmpLcsSrc,
|
|
|
|
aCmp.GetLen1(), aCmp.GetLen2(),
|
|
|
|
nLcsLen, CmpOptions.nIgnoreLen );
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
2011-12-22 17:27:32 +01:00
|
|
|
|
|
|
|
nLcsLen = aCmp.GetCharSequence( pTmpLcsDst, pTmpLcsSrc,
|
|
|
|
pLcsDst, pLcsSrc, nLcsLen );
|
|
|
|
|
|
|
|
delete[] pTmpLcsDst;
|
|
|
|
delete[] pTmpLcsSrc;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
2011-12-22 17:27:32 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
CharArrayComparator aCmp( &rDstNd, &rSrcNd );
|
|
|
|
LgstCommonSubseq aSeq( aCmp );
|
|
|
|
|
|
|
|
nLcsLen = aSeq.Find( pLcsDst, pLcsSrc );
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2011-12-22 17:27:32 +01:00
|
|
|
if( CmpOptions.nIgnoreLen )
|
|
|
|
{
|
|
|
|
nLcsLen = aSeq.IgnoreIsolatedPieces( pLcsDst, pLcsSrc, nDstLen,
|
|
|
|
nSrcLen, nLcsLen,
|
|
|
|
CmpOptions.nIgnoreLen );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// find the sum of the squares of the continuous substrings
|
|
|
|
int nSqSum = 0;
|
|
|
|
int nCnt = 1;
|
|
|
|
for( int i = 0; i < nLcsLen; i++ )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2011-12-22 17:27:32 +01:00
|
|
|
if( i != nLcsLen - 1 && pLcsDst[i] + 1 == pLcsDst[i + 1]
|
|
|
|
&& pLcsSrc[i] + 1 == pLcsSrc[i + 1] )
|
|
|
|
{
|
|
|
|
nCnt++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nSqSum += nCnt*nCnt;
|
|
|
|
nCnt = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't compare if there aren't enough similarities
|
|
|
|
if ( nAvgLen >= 8 && nSqSum*32 < nAvgLen*nAvgLen )
|
|
|
|
{
|
2012-10-20 23:12:12 +09:00
|
|
|
return false;
|
2011-12-22 17:27:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Show the differences
|
|
|
|
int nSkip = 0;
|
|
|
|
for( int i = 0; i <= nLcsLen; i++ )
|
|
|
|
{
|
|
|
|
int nDstFrom = i ? (pLcsDst[i - 1] + 1) : 0;
|
|
|
|
int nDstTo = ( i == nLcsLen ) ? nDstLen : pLcsDst[i];
|
|
|
|
int nSrcFrom = i ? (pLcsSrc[i - 1] + 1) : 0;
|
|
|
|
int nSrcTo = ( i == nLcsLen ) ? nSrcLen : pLcsSrc[i];
|
|
|
|
|
|
|
|
SwPaM aPam( rDstNd, nDstTo + nSkip );
|
|
|
|
|
|
|
|
if ( nDstFrom < nDstTo )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
SwPaM* pTmp = new SwPaM( *aPam.GetPoint(), rpInsRing );
|
|
|
|
if( !rpInsRing )
|
|
|
|
rpInsRing = pTmp;
|
|
|
|
pTmp->SetMark();
|
2011-12-22 17:27:32 +01:00
|
|
|
pTmp->GetMark()->nContent = nDstFrom + nSkip;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
|
2011-12-22 17:27:32 +01:00
|
|
|
if ( nSrcFrom < nSrcTo )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2011-12-22 17:27:32 +01:00
|
|
|
sal_Bool bUndo = pDstDoc->GetIDocumentUndoRedo().DoesUndo();
|
|
|
|
pDstDoc->GetIDocumentUndoRedo().DoUndo( sal_False );
|
|
|
|
SwPaM aCpyPam( rSrcNd, nSrcFrom );
|
|
|
|
aCpyPam.SetMark();
|
|
|
|
aCpyPam.GetPoint()->nContent = nSrcTo;
|
|
|
|
aCpyPam.GetDoc()->CopyRange( aCpyPam, *aPam.GetPoint(),
|
|
|
|
false );
|
|
|
|
pDstDoc->GetIDocumentUndoRedo().DoUndo( bUndo );
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
SwPaM* pTmp = new SwPaM( *aPam.GetPoint(), rpDelRing );
|
|
|
|
if( !rpDelRing )
|
|
|
|
rpDelRing = pTmp;
|
|
|
|
|
|
|
|
pTmp->SetMark();
|
2011-12-22 17:27:32 +01:00
|
|
|
pTmp->GetMark()->nContent = nDstTo + nSkip;
|
|
|
|
nSkip += nSrcTo - nSrcFrom;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
if( rpInsRing )
|
|
|
|
{
|
|
|
|
SwPaM* pCorr = (SwPaM*)rpInsRing->GetPrev();
|
|
|
|
if( *pCorr->GetPoint() == *pTmp->GetPoint() )
|
|
|
|
*pCorr->GetPoint() = *pTmp->GetMark();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-12-22 17:27:32 +01:00
|
|
|
|
|
|
|
delete[] pLcsDst;
|
|
|
|
delete[] pLcsSrc;
|
|
|
|
|
2012-10-20 23:12:12 +09:00
|
|
|
bRet = true;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
2011-12-22 17:27:32 +01:00
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
SwCompareData::~SwCompareData()
|
|
|
|
{
|
|
|
|
if( pDelRing )
|
|
|
|
{
|
|
|
|
while( pDelRing->GetNext() != pDelRing )
|
|
|
|
delete pDelRing->GetNext();
|
|
|
|
delete pDelRing;
|
|
|
|
}
|
|
|
|
if( pInsRing )
|
|
|
|
{
|
|
|
|
while( pInsRing->GetNext() != pInsRing )
|
|
|
|
delete pInsRing->GetNext();
|
|
|
|
delete pInsRing;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong SwCompareData::NextIdx( const SwNode* pNd )
|
2001-09-27 12:42:58 +00:00
|
|
|
{
|
|
|
|
if( pNd->IsStartNode() )
|
|
|
|
{
|
|
|
|
const SwSectionNode* pSNd;
|
|
|
|
if( pNd->IsTableNode() ||
|
|
|
|
( 0 != (pSNd = pNd->GetSectionNode() ) &&
|
|
|
|
( CONTENT_SECTION != pSNd->GetSection().GetType() ||
|
|
|
|
pSNd->GetSection().IsProtect() ) ) )
|
|
|
|
pNd = pNd->EndOfSectionNode();
|
|
|
|
}
|
|
|
|
return pNd->GetIndex() + 1;
|
|
|
|
}
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong SwCompareData::PrevIdx( const SwNode* pNd )
|
2001-09-27 12:42:58 +00:00
|
|
|
{
|
|
|
|
if( pNd->IsEndNode() )
|
|
|
|
{
|
|
|
|
const SwSectionNode* pSNd;
|
|
|
|
if( pNd->StartOfSectionNode()->IsTableNode() ||
|
|
|
|
( 0 != (pSNd = pNd->StartOfSectionNode()->GetSectionNode() ) &&
|
|
|
|
( CONTENT_SECTION != pSNd->GetSection().GetType() ||
|
|
|
|
pSNd->GetSection().IsProtect() ) ) )
|
|
|
|
pNd = pNd->StartOfSectionNode();
|
|
|
|
}
|
|
|
|
return pNd->GetIndex() - 1;
|
|
|
|
}
|
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
void SwCompareData::CheckRanges( CompareData& rData )
|
|
|
|
{
|
|
|
|
const SwNodes& rSrcNds = ((SwCompareData&)rData).rDoc.GetNodes();
|
|
|
|
const SwNodes& rDstNds = rDoc.GetNodes();
|
|
|
|
|
|
|
|
const SwNode& rSrcEndNd = rSrcNds.GetEndOfContent();
|
|
|
|
const SwNode& rDstEndNd = rDstNds.GetEndOfContent();
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nSrcSttIdx = NextIdx( rSrcEndNd.StartOfSectionNode() );
|
|
|
|
sal_uLong nSrcEndIdx = rSrcEndNd.GetIndex();
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nDstSttIdx = NextIdx( rDstEndNd.StartOfSectionNode() );
|
|
|
|
sal_uLong nDstEndIdx = rDstEndNd.GetIndex();
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
while( nSrcSttIdx < nSrcEndIdx && nDstSttIdx < nDstEndIdx )
|
|
|
|
{
|
|
|
|
const SwNode* pSrcNd = rSrcNds[ nSrcSttIdx ];
|
|
|
|
const SwNode* pDstNd = rDstNds[ nDstSttIdx ];
|
|
|
|
if( !SwCompareLine::CompareNode( *pSrcNd, *pDstNd ))
|
|
|
|
break;
|
|
|
|
|
|
|
|
nSrcSttIdx = NextIdx( pSrcNd );
|
|
|
|
nDstSttIdx = NextIdx( pDstNd );
|
|
|
|
}
|
|
|
|
|
2001-09-27 12:42:58 +00:00
|
|
|
nSrcEndIdx = PrevIdx( &rSrcEndNd );
|
|
|
|
nDstEndIdx = PrevIdx( &rDstEndNd );
|
2000-09-18 23:08:29 +00:00
|
|
|
while( nSrcSttIdx < nSrcEndIdx && nDstSttIdx < nDstEndIdx )
|
|
|
|
{
|
|
|
|
const SwNode* pSrcNd = rSrcNds[ nSrcEndIdx ];
|
|
|
|
const SwNode* pDstNd = rDstNds[ nDstEndIdx ];
|
|
|
|
if( !SwCompareLine::CompareNode( *pSrcNd, *pDstNd ))
|
|
|
|
break;
|
|
|
|
|
|
|
|
nSrcEndIdx = PrevIdx( pSrcNd );
|
|
|
|
nDstEndIdx = PrevIdx( pDstNd );
|
|
|
|
}
|
|
|
|
|
|
|
|
while( nSrcSttIdx <= nSrcEndIdx )
|
|
|
|
{
|
|
|
|
const SwNode* pNd = rSrcNds[ nSrcSttIdx ];
|
|
|
|
rData.InsertLine( new SwCompareLine( *pNd ) );
|
|
|
|
nSrcSttIdx = NextIdx( pNd );
|
|
|
|
}
|
|
|
|
|
|
|
|
while( nDstSttIdx <= nDstEndIdx )
|
|
|
|
{
|
|
|
|
const SwNode* pNd = rDstNds[ nDstSttIdx ];
|
|
|
|
InsertLine( new SwCompareLine( *pNd ) );
|
|
|
|
nDstSttIdx = NextIdx( pNd );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
void SwCompareData::ShowInsert( sal_uLong nStt, sal_uLong nEnd )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
SwPaM* pTmp = new SwPaM( ((SwCompareLine*)GetLine( nStt ))->GetNode(), 0,
|
|
|
|
((SwCompareLine*)GetLine( nEnd-1 ))->GetEndNode(), 0,
|
|
|
|
pInsRing );
|
|
|
|
if( !pInsRing )
|
|
|
|
pInsRing = pTmp;
|
|
|
|
|
2006-07-19 08:32:59 +00:00
|
|
|
// #i65201#: These SwPaMs are calculated smaller than needed, see comment below
|
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
void SwCompareData::ShowDelete( const CompareData& rData, sal_uLong nStt,
|
|
|
|
sal_uLong nEnd, sal_uLong nInsPos )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
SwNodeRange aRg(
|
|
|
|
((SwCompareLine*)rData.GetLine( nStt ))->GetNode(), 0,
|
|
|
|
((SwCompareLine*)rData.GetLine( nEnd-1 ))->GetEndNode(), 1 );
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uInt16 nOffset = 0;
|
2012-03-08 14:52:14 +01:00
|
|
|
const CompareLine* pLine = 0;
|
|
|
|
if( nInsPos >= 1 )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2012-03-08 14:52:14 +01:00
|
|
|
if( GetLineCount() == nInsPos )
|
|
|
|
{
|
|
|
|
pLine = GetLine( nInsPos-1 );
|
|
|
|
nOffset = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pLine = GetLine( nInsPos );
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const SwNode* pLineNd;
|
|
|
|
if( pLine )
|
2001-09-27 12:42:58 +00:00
|
|
|
{
|
|
|
|
if( nOffset )
|
|
|
|
pLineNd = &((SwCompareLine*)pLine)->GetEndNode();
|
|
|
|
else
|
|
|
|
pLineNd = &((SwCompareLine*)pLine)->GetNode();
|
|
|
|
}
|
2000-09-18 23:08:29 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
pLineNd = &rDoc.GetNodes().GetEndOfContent();
|
|
|
|
nOffset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
SwNodeIndex aInsPos( *pLineNd, nOffset );
|
|
|
|
SwNodeIndex aSavePos( aInsPos, -1 );
|
|
|
|
|
2009-07-28 13:59:44 +00:00
|
|
|
((SwCompareData&)rData).rDoc.CopyWithFlyInFly( aRg, 0, aInsPos );
|
2001-09-27 12:42:58 +00:00
|
|
|
rDoc.SetModified();
|
2012-10-15 23:31:02 +02:00
|
|
|
++aSavePos;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2006-07-19 08:32:59 +00:00
|
|
|
// #i65201#: These SwPaMs are calculated when the (old) delete-redlines are hidden,
|
|
|
|
// they will be inserted when the delete-redlines are shown again.
|
|
|
|
// To avoid unwanted insertions of delete-redlines into these new redlines, what happens
|
|
|
|
// especially at the end of the document, I reduce the SwPaM by one node.
|
|
|
|
// Before the new redlines are inserted, they have to expand again.
|
|
|
|
SwPaM* pTmp = new SwPaM( aSavePos.GetNode(), aInsPos.GetNode(), 0, -1, pDelRing );
|
2000-09-18 23:08:29 +00:00
|
|
|
if( !pDelRing )
|
|
|
|
pDelRing = pTmp;
|
|
|
|
|
|
|
|
if( pInsRing )
|
|
|
|
{
|
|
|
|
SwPaM* pCorr = (SwPaM*)pInsRing->GetPrev();
|
|
|
|
if( *pCorr->GetPoint() == *pTmp->GetPoint() )
|
2006-07-19 08:32:59 +00:00
|
|
|
{
|
|
|
|
SwNodeIndex aTmpPos( pTmp->GetMark()->nNode, -1 );
|
2010-03-09 13:27:17 +01:00
|
|
|
*pCorr->GetPoint() = SwPosition( aTmpPos );
|
2006-07-19 08:32:59 +00:00
|
|
|
}
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SwCompareData::CheckForChangesInLine( const CompareData& rData,
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong& rStt, sal_uLong& rEnd,
|
|
|
|
sal_uLong& rThisStt, sal_uLong& rThisEnd )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2011-12-22 17:27:32 +01:00
|
|
|
LineArrayComparator aCmp( (CompareData&)*this, rData, rThisStt, rThisEnd,
|
|
|
|
rStt, rEnd );
|
|
|
|
|
|
|
|
int nMinLen = std::min( aCmp.GetLen1(), aCmp.GetLen2() );
|
|
|
|
int *pLcsDst = new int[ nMinLen ];
|
|
|
|
int *pLcsSrc = new int[ nMinLen ];
|
|
|
|
|
|
|
|
FastCommonSubseq subseq( aCmp );
|
|
|
|
int nLcsLen = subseq.Find( pLcsDst, pLcsSrc );
|
|
|
|
for (int i = 0; i <= nLcsLen; i++)
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2011-12-22 17:27:32 +01:00
|
|
|
// Beginning of inserted lines (inclusive)
|
|
|
|
int nDstFrom = i ? pLcsDst[i - 1] + 1 : 0;
|
|
|
|
// End of inserted lines (exclusive)
|
|
|
|
int nDstTo = ( i == nLcsLen ) ? aCmp.GetLen1() : pLcsDst[i];
|
|
|
|
// Begining of deleted lines (inclusive)
|
|
|
|
int nSrcFrom = i ? pLcsSrc[i - 1] + 1 : 0;
|
|
|
|
// End of deleted lines (exclusive)
|
|
|
|
int nSrcTo = ( i == nLcsLen ) ? aCmp.GetLen2() : pLcsSrc[i];
|
|
|
|
|
|
|
|
if( i )
|
|
|
|
{
|
|
|
|
SwCompareLine* pDstLn = (SwCompareLine*)GetLine( rThisStt + nDstFrom - 1 );
|
|
|
|
SwCompareLine* pSrcLn = (SwCompareLine*)rData.GetLine( rStt + nSrcFrom - 1 );
|
|
|
|
|
|
|
|
// Show differences in detail for lines that
|
|
|
|
// were matched as only slightly different
|
|
|
|
if( !pDstLn->ChangesInLine( *pSrcLn, pInsRing, pDelRing ) )
|
|
|
|
{
|
|
|
|
ShowInsert( rThisStt + nDstFrom - 1, rThisStt + nDstFrom );
|
|
|
|
ShowDelete( rData, rStt + nSrcFrom - 1, rStt + nSrcFrom,
|
|
|
|
rThisStt + nDstFrom );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lines missing from source are inserted
|
|
|
|
if( nDstFrom != nDstTo )
|
|
|
|
{
|
|
|
|
ShowInsert( rThisStt + nDstFrom, rThisStt + nDstTo );
|
|
|
|
}
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2011-12-22 17:27:32 +01:00
|
|
|
// Lines missing from destination are deleted
|
|
|
|
if( nSrcFrom != nSrcTo )
|
|
|
|
{
|
|
|
|
ShowDelete( rData, rStt + nSrcFrom, rStt + nSrcTo, rThisStt + nDstTo );
|
|
|
|
}
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-17 15:06:54 +01:00
|
|
|
void SwCompareData::SetRedlinesToDoc( sal_Bool bUseDocInfo )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
SwPaM* pTmp = pDelRing;
|
2001-09-12 10:57:39 +00:00
|
|
|
|
2011-02-07 20:21:18 +01:00
|
|
|
// get the Author / TimeStamp from the "other" document info
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uInt16 nAuthor = rDoc.GetRedlineAuthor();
|
2011-12-01 21:03:42 +01:00
|
|
|
DateTime aTimeStamp( DateTime::SYSTEM );
|
2008-02-26 13:05:40 +00:00
|
|
|
SwDocShell *pDocShell(rDoc.GetDocShell());
|
2011-05-08 22:14:45 +02:00
|
|
|
OSL_ENSURE(pDocShell, "no SwDocShell");
|
2008-02-26 13:05:40 +00:00
|
|
|
if (pDocShell) {
|
|
|
|
uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
|
|
|
|
pDocShell->GetModel(), uno::UNO_QUERY_THROW);
|
|
|
|
uno::Reference<document::XDocumentProperties> xDocProps(
|
|
|
|
xDPS->getDocumentProperties());
|
2011-05-08 22:14:45 +02:00
|
|
|
OSL_ENSURE(xDocProps.is(), "Doc has no DocumentProperties");
|
2008-02-26 13:05:40 +00:00
|
|
|
|
|
|
|
if( bUseDocInfo && xDocProps.is() ) {
|
|
|
|
String aTmp( 1 == xDocProps->getEditingCycles()
|
|
|
|
? xDocProps->getAuthor()
|
|
|
|
: xDocProps->getModifiedBy() );
|
|
|
|
util::DateTime uDT( 1 == xDocProps->getEditingCycles()
|
|
|
|
? xDocProps->getCreationDate()
|
|
|
|
: xDocProps->getModificationDate() );
|
|
|
|
Date d(uDT.Day, uDT.Month, uDT.Year);
|
|
|
|
Time t(uDT.Hours, uDT.Minutes, uDT.Seconds, uDT.HundredthSeconds);
|
|
|
|
DateTime aDT(d,t);
|
|
|
|
|
|
|
|
if( aTmp.Len() )
|
|
|
|
{
|
|
|
|
nAuthor = rDoc.InsertRedlineAuthor( aTmp );
|
|
|
|
aTimeStamp = aDT;
|
|
|
|
}
|
2001-09-12 10:57:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
if( pTmp )
|
2001-09-12 10:57:39 +00:00
|
|
|
{
|
2007-09-27 07:33:25 +00:00
|
|
|
SwRedlineData aRedlnData( nsRedlineType_t::REDLINE_DELETE, nAuthor, aTimeStamp,
|
2001-09-12 10:57:39 +00:00
|
|
|
aEmptyStr, 0, 0 );
|
2000-09-18 23:08:29 +00:00
|
|
|
do {
|
2006-07-19 08:32:59 +00:00
|
|
|
// #i65201#: Expand again, see comment above.
|
|
|
|
if( pTmp->GetPoint()->nContent == 0 )
|
|
|
|
{
|
|
|
|
pTmp->GetPoint()->nNode++;
|
|
|
|
pTmp->GetPoint()->nContent.Assign( pTmp->GetCntntNode(), 0 );
|
|
|
|
}
|
2011-04-16 22:42:13 -03:00
|
|
|
// #i101009#
|
2010-05-17 15:50:18 +02:00
|
|
|
// prevent redlines that end on structural end node
|
|
|
|
if (& rDoc.GetNodes().GetEndOfContent() ==
|
|
|
|
& pTmp->GetPoint()->nNode.GetNode())
|
|
|
|
{
|
|
|
|
pTmp->GetPoint()->nNode--;
|
|
|
|
SwCntntNode *const pContentNode( pTmp->GetCntntNode() );
|
|
|
|
pTmp->GetPoint()->nContent.Assign( pContentNode,
|
|
|
|
(pContentNode) ? pContentNode->Len() : 0 );
|
|
|
|
}
|
2006-07-19 08:32:59 +00:00
|
|
|
|
2006-08-14 14:55:46 +00:00
|
|
|
rDoc.DeleteRedline( *pTmp, false, USHRT_MAX );
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2010-11-25 14:31:08 +01:00
|
|
|
if (rDoc.GetIDocumentUndoRedo().DoesUndo())
|
|
|
|
{
|
2011-02-07 13:06:08 +01:00
|
|
|
SwUndo *const pUndo(new SwUndoCompDoc( *pTmp, sal_False )) ;
|
2010-11-25 14:31:08 +01:00
|
|
|
rDoc.GetIDocumentUndoRedo().AppendUndo(pUndo);
|
|
|
|
}
|
2006-08-14 14:55:46 +00:00
|
|
|
rDoc.AppendRedline( new SwRedline( aRedlnData, *pTmp ), true );
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
} while( pDelRing != ( pTmp = (SwPaM*)pTmp->GetNext() ));
|
2001-09-12 10:57:39 +00:00
|
|
|
}
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
pTmp = pInsRing;
|
|
|
|
if( pTmp )
|
|
|
|
{
|
2006-07-19 08:32:59 +00:00
|
|
|
do {
|
|
|
|
if( pTmp->GetPoint()->nContent == 0 )
|
|
|
|
{
|
|
|
|
pTmp->GetPoint()->nNode++;
|
|
|
|
pTmp->GetPoint()->nContent.Assign( pTmp->GetCntntNode(), 0 );
|
|
|
|
}
|
2011-04-16 22:42:13 -03:00
|
|
|
// #i101009#
|
2010-05-17 15:50:18 +02:00
|
|
|
// prevent redlines that end on structural end node
|
|
|
|
if (& rDoc.GetNodes().GetEndOfContent() ==
|
|
|
|
& pTmp->GetPoint()->nNode.GetNode())
|
|
|
|
{
|
|
|
|
pTmp->GetPoint()->nNode--;
|
|
|
|
SwCntntNode *const pContentNode( pTmp->GetCntntNode() );
|
|
|
|
pTmp->GetPoint()->nContent.Assign( pContentNode,
|
|
|
|
(pContentNode) ? pContentNode->Len() : 0 );
|
|
|
|
}
|
2006-07-19 08:32:59 +00:00
|
|
|
} while( pInsRing != ( pTmp = (SwPaM*)pTmp->GetNext() ));
|
2007-09-27 07:33:25 +00:00
|
|
|
SwRedlineData aRedlnData( nsRedlineType_t::REDLINE_INSERT, nAuthor, aTimeStamp,
|
2001-09-12 10:57:39 +00:00
|
|
|
aEmptyStr, 0, 0 );
|
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// combine consecutive
|
2000-09-18 23:08:29 +00:00
|
|
|
if( pTmp->GetNext() != pInsRing )
|
|
|
|
{
|
|
|
|
const SwCntntNode* pCNd;
|
|
|
|
do {
|
|
|
|
SwPosition& rSttEnd = *pTmp->End(),
|
|
|
|
& rEndStt = *((SwPaM*)pTmp->GetNext())->Start();
|
|
|
|
if( rSttEnd == rEndStt ||
|
|
|
|
(!rEndStt.nContent.GetIndex() &&
|
|
|
|
rEndStt.nNode.GetIndex() - 1 == rSttEnd.nNode.GetIndex() &&
|
|
|
|
0 != ( pCNd = rSttEnd.nNode.GetNode().GetCntntNode() )
|
|
|
|
? rSttEnd.nContent.GetIndex() == pCNd->Len()
|
|
|
|
: 0 ))
|
|
|
|
{
|
|
|
|
if( pTmp->GetNext() == pInsRing )
|
|
|
|
{
|
2011-11-04 14:46:42 +01:00
|
|
|
// are consecutive, so combine
|
2000-09-18 23:08:29 +00:00
|
|
|
rEndStt = *pTmp->Start();
|
|
|
|
delete pTmp;
|
|
|
|
pTmp = pInsRing;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-11-19 12:05:18 +01:00
|
|
|
// are consecutive, so combine
|
2000-09-18 23:08:29 +00:00
|
|
|
rSttEnd = *((SwPaM*)pTmp->GetNext())->End();
|
|
|
|
delete pTmp->GetNext();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pTmp = (SwPaM*)pTmp->GetNext();
|
|
|
|
} while( pInsRing != pTmp );
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
2006-08-14 14:55:46 +00:00
|
|
|
if( rDoc.AppendRedline( new SwRedline( aRedlnData, *pTmp ), true) &&
|
2010-11-25 14:31:08 +01:00
|
|
|
rDoc.GetIDocumentUndoRedo().DoesUndo())
|
|
|
|
{
|
2011-02-07 13:06:08 +01:00
|
|
|
SwUndo *const pUndo(new SwUndoCompDoc( *pTmp, sal_True ));
|
2010-11-25 14:31:08 +01:00
|
|
|
rDoc.GetIDocumentUndoRedo().AppendUndo(pUndo);
|
|
|
|
}
|
2000-09-18 23:08:29 +00:00
|
|
|
} while( pInsRing != ( pTmp = (SwPaM*)pTmp->GetNext() ));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// Returns (the difference count?) if something is different
|
2000-09-18 23:08:29 +00:00
|
|
|
long SwDoc::CompareDoc( const SwDoc& rDoc )
|
|
|
|
{
|
|
|
|
if( &rDoc == this )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
long nRet = 0;
|
|
|
|
|
2011-12-22 17:27:32 +01:00
|
|
|
// Get comparison options
|
|
|
|
CmpOptions.eCmpMode = SW_MOD()->GetCompareMode();
|
|
|
|
if( CmpOptions.eCmpMode == SVX_CMP_AUTO )
|
|
|
|
{
|
|
|
|
if( getRsidRoot() == rDoc.getRsidRoot() )
|
|
|
|
{
|
|
|
|
CmpOptions.eCmpMode = SVX_CMP_BY_CHAR;
|
|
|
|
CmpOptions.bUseRsid = true;
|
|
|
|
CmpOptions.nIgnoreLen = 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CmpOptions.eCmpMode = SVX_CMP_BY_WORD;
|
|
|
|
CmpOptions.bUseRsid = false;
|
|
|
|
CmpOptions.nIgnoreLen = 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CmpOptions.bUseRsid = getRsidRoot() == rDoc.getRsidRoot() && SW_MOD()->IsUseRsid();
|
|
|
|
CmpOptions.nIgnoreLen = SW_MOD()->IsIgnorePieces() ? SW_MOD()->GetPieceLen() : 0;
|
|
|
|
}
|
|
|
|
|
2010-11-25 14:31:08 +01:00
|
|
|
GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_Bool bDocWasModified = IsModified();
|
2000-09-18 23:08:29 +00:00
|
|
|
SwDoc& rSrcDoc = (SwDoc&)rDoc;
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_Bool bSrcModified = rSrcDoc.IsModified();
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2007-09-27 07:33:25 +00:00
|
|
|
RedlineMode_t eSrcRedlMode = rSrcDoc.GetRedlineMode();
|
|
|
|
rSrcDoc.SetRedlineMode( nsRedlineMode_t::REDLINE_SHOW_INSERT );
|
|
|
|
SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT));
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
SwCompareData aD0( rSrcDoc );
|
|
|
|
SwCompareData aD1( *this );
|
|
|
|
|
|
|
|
aD1.CompareLines( aD0 );
|
|
|
|
|
|
|
|
nRet = aD1.ShowDiffs( aD0 );
|
|
|
|
|
|
|
|
if( nRet )
|
|
|
|
{
|
2007-09-27 07:33:25 +00:00
|
|
|
SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_ON |
|
|
|
|
nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE));
|
2006-08-14 14:55:46 +00:00
|
|
|
|
2007-09-27 07:33:25 +00:00
|
|
|
aD1.SetRedlinesToDoc( !bDocWasModified );
|
2001-09-27 12:42:58 +00:00
|
|
|
SetModified();
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rSrcDoc.SetRedlineMode( eSrcRedlMode );
|
2007-09-27 07:33:25 +00:00
|
|
|
SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE));
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
if( !bSrcModified )
|
|
|
|
rSrcDoc.ResetModified();
|
|
|
|
|
2010-11-25 14:31:08 +01:00
|
|
|
GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL);
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
return nRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
class _SaveMergeRedlines : public Ring
|
|
|
|
{
|
|
|
|
const SwRedline* pSrcRedl;
|
|
|
|
SwRedline* pDestRedl;
|
|
|
|
public:
|
|
|
|
_SaveMergeRedlines( const SwNode& rDstNd,
|
|
|
|
const SwRedline& rSrcRedl, Ring* pRing );
|
2011-02-07 13:06:08 +01:00
|
|
|
sal_uInt16 InsertRedline();
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
SwRedline* GetDestRedline() { return pDestRedl; }
|
|
|
|
};
|
|
|
|
|
|
|
|
_SaveMergeRedlines::_SaveMergeRedlines( const SwNode& rDstNd,
|
|
|
|
const SwRedline& rSrcRedl, Ring* pRing )
|
|
|
|
: Ring( pRing ), pSrcRedl( &rSrcRedl )
|
|
|
|
{
|
|
|
|
SwPosition aPos( rDstNd );
|
|
|
|
|
|
|
|
const SwPosition* pStt = rSrcRedl.Start();
|
|
|
|
if( rDstNd.IsCntntNode() )
|
|
|
|
aPos.nContent.Assign( ((SwCntntNode*)&rDstNd), pStt->nContent.GetIndex() );
|
|
|
|
pDestRedl = new SwRedline( rSrcRedl.GetRedlineData(), aPos );
|
|
|
|
|
2007-09-27 07:33:25 +00:00
|
|
|
if( nsRedlineType_t::REDLINE_DELETE == pDestRedl->GetType() )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2011-11-04 14:46:42 +01:00
|
|
|
// mark the area as deleted
|
2000-09-18 23:08:29 +00:00
|
|
|
const SwPosition* pEnd = pStt == rSrcRedl.GetPoint()
|
|
|
|
? rSrcRedl.GetMark()
|
|
|
|
: rSrcRedl.GetPoint();
|
|
|
|
|
|
|
|
pDestRedl->SetMark();
|
|
|
|
pDestRedl->GetPoint()->nNode += pEnd->nNode.GetIndex() -
|
|
|
|
pStt->nNode.GetIndex();
|
|
|
|
pDestRedl->GetPoint()->nContent.Assign( pDestRedl->GetCntntNode(),
|
|
|
|
pEnd->nContent.GetIndex() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-07 13:06:08 +01:00
|
|
|
sal_uInt16 _SaveMergeRedlines::InsertRedline()
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uInt16 nIns = 0;
|
2000-09-18 23:08:29 +00:00
|
|
|
SwDoc* pDoc = pDestRedl->GetDoc();
|
|
|
|
|
2007-09-27 07:33:25 +00:00
|
|
|
if( nsRedlineType_t::REDLINE_INSERT == pDestRedl->GetType() )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
2011-11-04 14:46:42 +01:00
|
|
|
// the part was inserted so copy it from the SourceDoc
|
2010-11-25 14:31:10 +01:00
|
|
|
::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
SwNodeIndex aSaveNd( pDestRedl->GetPoint()->nNode, -1 );
|
|
|
|
xub_StrLen nSaveCnt = pDestRedl->GetPoint()->nContent.GetIndex();
|
|
|
|
|
2007-09-27 07:33:25 +00:00
|
|
|
RedlineMode_t eOld = pDoc->GetRedlineMode();
|
|
|
|
pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
|
2000-09-18 23:08:29 +00:00
|
|
|
|
CWS-TOOLING: integrate CWS odfmetadata3
2009-09-11 Michael Stahl merge DEV300_m58
2009-09-07 Michael Stahl SwFmtFld::Modify(): do nothing on RES_OBJECTDYING
2009-08-27 Michael Stahl #i91565#, #i91566#: TextPortionEnumerationTest.java: add test document
2009-08-27 Michael Stahl #i91565#, #i91566#: add complex test: TextPortionEnumerationTest.java
2009-08-27 Michael Stahl CLiteral::initialize(): zero-length literals probably not an error
2009-08-27 Michael Stahl #i91565#, #i91566#: offapi: new InContentMetadata and MetadataField services
adapt TextPortion for InContentMetadata
2009-08-27 Michael Stahl #i91564#: xmloff: load/store xml:id and RDFa for text:bookmark(-start).
2009-08-27 Michael Stahl #i91564#: sw core: add support for xml:id at bookmarks:
sw::mark::Bookmark: derive from Metadatable.
SwHistoryBookmark, SaveBookmark: store a MetadatableUndo.
ndcopy.cxx: lcl_CopyBookmarks(): copy the xml:id.
SwXBookmark: derive from MetadatableMixin.
2009-08-27 Michael Stahl #i91565#, #i91566#: xmloff: refactor ruby import so nested meta(-field) works:
remove XMLRubyHint_Impl.
XMLImpRubyContext_Impl::~XMLImpRubyContext_Impl(): insert ruby directly.
2009-08-27 Michael Stahl #i91565#, #i91566#: xmloff: fix text:meta(-field) import/export:
new XMLTextParagraphExport::exportTextField() overload for XTextField.
CreateAndInsertMark(): set xml:id after insertion.
fix meta(-field) service names, bugs etc.
2009-08-27 Michael Stahl #i91565#, #i91566#: sw text formatting: paint background of meta(-field) body:
SwFont: add member m_nMetaCount.
txttypes.hxx: add POR_META.
atrstck.cxx: handle RES_TXTATR_META(FIELD).
itrform2.cxx: SwTxtFormatter::WhichTxtPor(): create new class SwMetaPortion.
2009-08-27 Michael Stahl #i91566#: sw text formatting: display meta-field prefix and suffix:
SwAttrIter::GetAttr(): replace with call to GetTxtAttrForCharAt().
SwTxtFormatter::NewExtraPortion(): handle meta-field prefix.
SwTxtFormatter: new member m_nHintEndIndex.
SwTxtFormatter::WhichFirstPortion(): call TryNewNoLengthPortion().
SwTxtFormatter::TryNewNoLengthPortion(): new; handle suffix of meta-field.
SwTxtFormatter::UnderFlow(): UGLY HACK: decrement m_nHintEndIndex.
SwFldPortion: add flag m_bNoLength: portion has zero length (for suffix).
2009-08-27 Michael Stahl #i91565#, #i91566#: extend text:meta(-field) uno wrapper with XText interface:
unoobj.hxx: new CursorType CURSOR_META.
unoobj2.cxx: refactor SwXText implementation to ensure that when the SwXText
belongs to a SwXMeta, content is always inserted inside the meta(-field).
unoobj.cxx: new SwXTextCursor::ForceIntoMeta(): cursor stays in meta(-field).
unometa.hxx: SwXMeta implements XText, forwarding to a member SwXMetaText.
DocInsertStringSplitCR(), SwX*::attachToRange(), SwX*::DeleteAndInsert():
use FORCEHINTEXPAND hack to ensure insert into the meta(-field) at the end.
2009-08-27 Michael Stahl #i91565#, #i91566#: add text:meta(-field) uno wrapper to sw:
fmtmeta.hxx, fmtatr2.cxx: new class sw::MetaField, new sw::MetaFieldManager.
doc.hxx, docnew.cxx: new SwDoc::GetMetaFieldManager().
unocoll.hxx,.cxx: new SW_SERVICE_FIELDTYPE_METAFIELD, SW_SERVICE_TYPE_META.
unomap.hxx,.cxx: new PROPERTY_MAP_METAFIELD.
unoprnms.hxx: new UNO_NAME_META.
unoport.hxx: new PORTION_META; add "InContentMetadata" prop to SwXTextPortion.
new unometa.hxx: new class SwXMeta and SwXMetaField.
unofield.cxx: SwXFieldEnumeration: include meta-fields.
unoportenum.cxx: handle RES_TXTATR_META(FIELD) by using a portion list stack.
unotext.cxx: SwXText::insertTextContent(): handle meta(-field) as attribute.
2009-08-27 Michael Stahl #i91565#, #i91566#: ndhints.cxx: remove sort number from SwTxtAttrNesting
2009-08-27 Michael Stahl #i91565#, #i91566#: add support for hints with end and CH_TXTATR to sw core:
doc.hxx, docedt.cxx: replace SwDoc::Delete(), DeleteAndJoin(), ReplaceRange()
with wrappers that split at left-overlapped end+CH_TXTATR hints.
txatbase.hxx: new member SwTxtAttr::m_bHasDummyChar.
ndtxt.hxx: rename SwTxtNode::GetTxtAttr() to GetTxtAttrForCharAt().
ndtxt.cxx: SwTxtNode::CopyText(): copy end+CH_TXTATR hints iff copy CH_TXTATR.
txtatr2.cxx, thints.cxx: SwTxtMeta gets a CH_TXTATR.
2009-08-27 Michael Stahl #i91565#, #i91566#: add text:meta(-field) to sw core:
txatbase.hxx: new member SwTxtAttr::m_bNesting.
hintids.hxx: new ids RES_TXTATR_META, RES_TXTATR_METAFIELD.
txtatr.hxx: new base class SwTxtAttrNesting.
new hint SwTxtMeta.
SwTxtRuby derives from SwTxtAttrNesting.
txtinet.hxx: SwTxtINetFmt derives from SwTxtAttrNesting.
new header fmtmeta.hxx: new pool item SwFmtMeta. new class sw::Meta.
ndhints.hxx, thints.cxx: new method SwpHints::TryInsertNesting().
thints.cxx: refactoring: BuildPortions() no longer handles Ruby/Hyperlink,
but TryInsertNesting(), which also handles meta(-field).
SwTxtNode::InsertItem(): check if the hint is actually inserted.
ndhints.cxx: sort nesting hints based on sort number.
ndtxt.cxx: lcl_CopyHint(): handle copy of meta/meta-field.
2009-08-27 Michael Stahl enable expanding hints with m_bLockExpandFlag set:
add new InsertFlag: INS_FORCEHINTEXPAND.
add new SetAttrMode: SETATTR_FORCEHINTEXPAND.
rename SwEditShell::Insert() to Insert2() because changed signature fails
to compile when SwWrtShell tries to overwrite these non-virtual members...
SwWrtShell::Insert() sets FOCEHINTEXPAND if range was selected/deleted.
adapt SwUndoInsert to store flags.
2009-08-27 Michael Stahl change formal parameters of item insertion methods to type SetAttrMode
2009-08-27 Michael Stahl fix incorrect resetting of text attributes in SwUndoInsSection, SwUndoInserts
2009-08-27 Michael Stahl clean up SwTxtNode::CutImpl() and lcl_CopyHint()
2009-08-27 Michael Stahl rename SwDoc::Copy() to CopyRange(), and _Copy() to CopyImpl()
2009-08-27 Michael Stahl rename SwNodes::Move() to MoveRange(), and remove unused parameter
2009-08-27 Michael Stahl rename SwDoc::Move() to MoveRange()/MoveNodeRange()
2009-08-27 Michael Stahl rename SwDoc::Insert() to InsertString(), and remove sal_Unicode variant
2009-08-27 Michael Stahl rename SwDoc::Insert() to InsertPoolItem()/InsertItemSet()/InsertSwSection()
2009-08-27 Michael Stahl rename SwDoc::Replace() to ReplaceRange()
2009-08-27 Michael Stahl remove SwDoc::Overwrite() sal_Unicode variant
2009-08-27 Michael Stahl split up SwDoc::DeleteAndJoin(): factor out DeleteAndJoinWithRedline()
2009-08-27 Michael Stahl rename overloaded SwDoc::Delete() to DeleteRange()/DeleteTOXMark()
2009-08-27 Michael Stahl rename SwTxtNode::Copy() to CopyText()
2009-08-27 Michael Stahl rename SwTxtNode::Cut() to CutText(), and _Cut() to CutImpl()
2009-08-27 Michael Stahl rename SwTxtNode::Delete() to DeleteAttribute()/DeleteAttributes()
2009-08-27 Michael Stahl rename SwTxtNode::Replace() to ReplaceText(), and remove the xub_Unicode variant
2009-08-27 Michael Stahl rename SwTxtNode::Erase() to EraseText()
2009-08-27 Michael Stahl rename SwTxtNode::Insert() to InsertText(), and remove the xub_Unicode variant
2009-08-27 Michael Stahl clean up SwTxtNode::Update()
2009-08-27 Michael Stahl remove SwTxtAttr::RemoveFromPool() and make destructor non-public,
to be invoked by new method SwTxtAttr::Destroy()
2009-08-27 Michael Stahl ensure that SwDoc::Insert() for item (set) returns success indicator:
replace SwRegHistory constructor with method InsertItems(), returning bool.
refactor InsAttr() so that it checks if InsertItems() succeeds.
2009-08-27 Michael Stahl move SwXTextPortionEnumeration from unoobj.hxx to unoport.hxx
2009-08-27 Michael Stahl add missing SolarMutex in SwXTextPortion methods
2009-08-27 Michael Stahl SwXTextPortion: new member m_xTextField (so the TextField property need not
be returned indirectly via SwUnoCursorHelper).
factor out function CreateSwXTextField().
2009-08-27 Michael Stahl SwXTextPortion: remove PORTION_CONTROL_CHAR and implementation of XTextField
2009-08-27 Michael Stahl remove obsolete hint SwTxtHardBlank and formats SwFmtHardBlank/SwFmtSoftHyph
2009-08-27 Michael Stahl clean up SwTxtAttr and friends:
remove many accessor methods for obsolete (due to autofmt) char format items.
remove unused flag SwTxtAttr::m_bDontMergeAttr.
MakeRedlineTxtAttr() now dedicated function, no longer calls MakeTxtAttr().
2009-08-27 Michael Stahl remove obsolete attribute SwTxt2Lines
2009-08-27 Michael Stahl SwXTextPortionEnumeration: finish refactoring CreatePortions
change ExportHints so it always returns a text portion for hint w/ CH_TXTATR.
remove special case for handling end of paragraph.
unfortunately had to refactor the fieldmarks export as well (got in the way).
2009-08-27 Michael Stahl SwXTextPortionEnumeration: refactor CreatePortions: frames export
extract function ExportFrames() from CreatePortions().
remove (un)dead code that calls evil MovePara(fnParaCurr, fnParaEnd)
2009-08-27 Michael Stahl clean up SwXParaFrameEnumeration
2009-08-27 Michael Stahl CollectFrameAtNode: replace SwDependArr with STL based FrameDependList_t
2009-08-27 Michael Stahl SwXTextPortionEnumeration: tweak refmark/toxmark export
so ExportHints returns the portion for point marks
2009-08-27 Michael Stahl clean up SwXTextPortionEnumeration:
prefix members, remove casts, replace SvWeirdArray with STL, etc.
make CreatePortions() method a function, and remove lots of members.
extract fieldmarks function from CreatePortions.
2009-08-27 Michael Stahl remove FOREACHUNOPAM_START/END macros
2009-08-27 Michael Stahl clean up SwXTextPortion:
prefix members, remove casts, etc.
remove SwXRubyPortion: replace it with another SwXTextPortion constructor
2009-08-27 Michael Stahl #i102541# SwXReferenceMark::InsertRefMark(): use flag SETATTR_DONTEXPAND
2009-08-27 Michael Stahl rename SwTxtNode::Insert to SwTxtNode::InsertHint, and
fix constness in SwTxtNode::InsertItem
2009-08-27 Michael Stahl turn SwTxtNode::MakeTxtAttr() methods into global functions in ndhints.hxx
2009-08-27 Michael Stahl remove obsolete sw/inc/bookmrk.hxx
2009-08-27 Michael Stahl pam.cxx: fix ComparePosition functions (returned wrong result in one case)
2009-08-27 Michael Stahl #i103613# only import RDF metadata on normal open of a document
2009-09-11 kz CWS-TOOLING: integrate CWS impress176
2009-09-08 20:18:24 +0200 sj r275957 : fixed warning (shadowed variable)
2009-09-08 18:02:05 +0200 cl r275948 : #i104315# added missing tab pages
2009-09-08 17:35:18 +0200 cl r275947 : #i104866# fixed angle import
2009-09-08 17:32:53 +0200 cl r275946 : #i104841# fixed angle import
2009-09-08 17:01:25 +0200 cl r275943 : #i103935# fixed the SID_EVENTCONFIG mess
2009-09-08 14:32:57 +0200 sj r275928 : #i104685# only comments
2009-09-07 12:37:36 +0200 sj r275886 : #i104683# fixed import of bold/italic attributes for normal text shapes
2009-09-04 15:07:46 +0200 sj r275808 : #104689# fixed bullet color problem
2009-09-03 15:25:07 +0200 sj r275753 : #160200# added vertical alignment of table cells
2009-09-11 kz CWS-TOOLING: integrate CWS dv14
2009-09-10 15:16:32 +0200 sg r276035 : #160513# updated wfs scheme to accept ports
2009-09-10 07:41:47 +0200 dv r276019 : #i104942# Better renaming algorithmen
2009-08-31 13:41:11 +0200 dv r275604 : #160505# Setting APP1PRODUCTNAME must not overwrite APP1PRODUCTDEF
2009-09-11 kz CWS-TOOLING: integrate CWS jl131
2009-09-02 16:42:40 +0200 jl r275720 : #i97896#
2009-08-31 13:01:53 +0200 jl r275599 : CWS-TOOLING: rebase CWS jl131 to trunk@275331 (milestone: DEV300:m56)
2009-07-31 14:35:30 +0200 jl r274531 : CWS-TOOLING: rebase CWS jl131 to trunk@274203 (milestone: DEV300:m53)
2009-07-23 14:20:32 +0200 jl r274272 : #i79839# better error text when trying to modify shared layer without having write permission, eg. unopkg add --shared, unopkg remove --shared, unopkg reinstall --shared
2009-07-22 16:38:02 +0200 jl r274252 : #i97896# localize error message for lock file
2009-07-22 16:37:22 +0200 jl r274251 : #i80462# unprecise wording in updatedialog
2009-07-22 16:36:06 +0200 jl r274250 : #i97896# localize error message for lock file
2009-07-22 16:35:20 +0200 jl r274249 : #i97896# localize error message for lock file
2009-07-22 15:07:30 +0200 jl r274242 : #i98873# minimum java version is 1.5 since OOo 3.0
2009-09-11 kz CWS-TOOLING: integrate CWS changehc
2009-08-31 19:38:50 +0200 pl r275633 : remove dbug printf
2009-08-31 17:41:50 +0200 pl r275623 : CWS-TOOLING: rebase CWS changehc to trunk@275331 (milestone: DEV300:m56)
2009-07-15 19:45:46 +0200 pl r274028 : #i35482# use HC flag to decide high contrast mode
2009-07-15 17:40:52 +0200 pl r274020 : #i35482# use HC flag to decide high contrast mode
2009-07-15 17:39:50 +0200 pl r274019 : #i35482# update autohc correctly in MergeSystemSettings
2009-07-15 17:38:57 +0200 pl r274018 : #i35482# update autohc correctly in MergeSystemSettings
2009-09-11 kz CWS-TOOLING: integrate CWS notes10
2009-08-24 07:25:57 +0200 mod r275287 : 2009-07-26 02:38:32 +0200 mod r274343 : #i#i103645#
2009-07-26 02:01:53 +0200 mod r274342 : #i103645#
2009-07-26 01:52:42 +0200 mod r274341 : #i103490#
2009-07-22 08:31:48 +0200 mod r274215 : #i103373#
2009-07-15 00:55:11 +0200 mod r273987 : #i101419#
2009-07-14 07:07:55 +0200 mod r273956 : #i101419#
2009-07-14 07:07:43 +0200 mod r273955 : #i101419#
2009-07-14 07:02:10 +0200 mod r273954 : changes from notes9
2009-07-14 06:14:25 +0200 mod r273953 : #i103476#
2009-09-11 kz CWS-TOOLING: integrate CWS ab70
2009-09-10 15:12:54 +0200 jsk r276034 : #i85434# - mandatory automatic update test
2009-09-10 15:11:06 +0200 jsk r276033 : #i85434# - mandatory automatic update test
2009-09-02 09:49:24 +0200 ab r275698 : #i85434# Dialog Import
2009-09-11 kz CWS-TOOLING: integrate CWS hb32bugs02
2009-09-02 Henning Brinkmann #i102420# revert changes
2009-08-26 Henning Brinkmann merged DEV300_m56
2009-08-19 Henning Brinkmann merged DEV300_m55
2009-08-14 Henning Brinkmann merged changes from wntmsci12
2009-08-12 Henning Brinkmann Implemented NoSpaceEdit constructor and destructor in .cxx to allow compile with debug on wntmsci12.
2009-08-12 Henning Brinkmann Added some SW_DLLPUBLIC to make compilable on wntmsci12.
2009-08-11 Henning Brinkmann #i102420# dbg_out: surround output for SwNodes with <nodes-array>.
2009-08-10 Henning Brinkmann #i102420# rewritten debug output for SwNodes.
2009-08-07 Henning Brinkmann #i102420# debug _MoveNodes: output the destination, too. Break after two iterations.
2009-08-07 Henning Brinkmann #i102420# _MoveNodes: Additionally check if destination index is inside source => false
Check if current range was already handled => loop
Debug output current range
2009-08-06 Henning Brinkmann merged DEV300_m54
2009-08-06 Henning Brinkmann added master fix
2009-08-06 Henning Brinkmann debug output for SwNodeRange
2009-08-04 Henning Brinkmann #i102844# robustness: check for NULL pointer to prevent crash
2009-08-03 Henning Brinkmann #i103475# applied patch and verified
2009-08-03 Henning Brinkmann Removed code preventing build of sw with DEBUG.
2009-09-11 convert-repo update tags
2009-09-10 kz CWS-TOOLING: integrate CWS os2port06dev300
2009-09-05 22:49:00 +0200 ydario r275858 : #i99588# applied os2port06 diff to DEV300 tree.
2009-09-10 kz CWS-TOOLING: integrate CWS mingwport23
2009-08-29 07:07:53 +0200 tono r275555 : i#104522: mingw port graphite
2009-08-29 07:07:26 +0200 tono r275554 : i#104522: mingw port printf format fix
2009-09-10 kz CWS-TOOLING: integrate CWS mh232
2009-08-26 03:52:57 +0200 mh r275385 : #i102182# FreeBSD patch
2009-08-26 03:43:20 +0200 mh r275384 : #i101333# patch for FreeBSD
2009-08-26 03:11:20 +0200 mh r275383 : #i39230
2009-08-26 03:07:51 +0200 mh r275382 : #i39230# more space for initials field
2009-08-26 02:41:19 +0200 mh r275380 : #i39230# use vos::osecurity for reading the user name
2009-08-18 22:06:00 +0200 mh r275130 : #i104243#, line ending problem with newer perl
2009-08-18 21:53:21 +0200 mh r275129 : #i39230# read initials via getpwnam
2009-08-18 21:34:05 +0200 mh r275128 : enable CAIROCANVAS for Linux and Mac, #i88613#
2009-08-17 18:02:59 +0200 mh r275067 : #i95498# make compile with gcc3
2009-09-10 kz CWS-TOOLING: integrate CWS tkr24
2009-09-07 14:31:06 +0200 is r275898 : #160081# adding NO_LICENSE_INTO_COPYRIGHT
2009-09-10 releng #i10000# change KeyMapping to SingletonRef<framework::KeyMapping>
2009-09-11 convert-repo update tags
2009-09-10 kz CWS-TOOLING: integrate CWS os2port06dev300
2009-09-05 22:49:00 +0200 ydario r275858 : #i99588# applied os2port06 diff to DEV300 tree.
2009-09-10 kz CWS-TOOLING: integrate CWS mingwport23
2009-08-29 07:07:53 +0200 tono r275555 : i#104522: mingw port graphite
2009-08-29 07:07:26 +0200 tono r275554 : i#104522: mingw port printf format fix
2009-09-10 kz CWS-TOOLING: integrate CWS mh232
2009-08-26 03:52:57 +0200 mh r275385 : #i102182# FreeBSD patch
2009-08-26 03:43:20 +0200 mh r275384 : #i101333# patch for FreeBSD
2009-08-26 03:11:20 +0200 mh r275383 : #i39230
2009-08-26 03:07:51 +0200 mh r275382 : #i39230# more space for initials field
2009-08-26 02:41:19 +0200 mh r275380 : #i39230# use vos::osecurity for reading the user name
2009-08-18 22:06:00 +0200 mh r275130 : #i104243#, line ending problem with newer perl
2009-08-18 21:53:21 +0200 mh r275129 : #i39230# read initials via getpwnam
2009-08-18 21:34:05 +0200 mh r275128 : enable CAIROCANVAS for Linux and Mac, #i88613#
2009-08-17 18:02:59 +0200 mh r275067 : #i95498# make compile with gcc3
2009-09-10 kz CWS-TOOLING: integrate CWS tkr24
2009-09-07 14:31:06 +0200 is r275898 : #160081# adding NO_LICENSE_INTO_COPYRIGHT
2009-09-10 releng #i10000# change KeyMapping to SingletonRef<framework::KeyMapping>
2009-09-11 14:29:45 +00:00
|
|
|
pSrcRedl->GetDoc()->CopyRange(
|
|
|
|
*const_cast<SwPaM*>(static_cast<const SwPaM*>(pSrcRedl)),
|
|
|
|
*pDestRedl->GetPoint(), false );
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
pDoc->SetRedlineMode_intern( eOld );
|
|
|
|
|
|
|
|
pDestRedl->SetMark();
|
2012-10-15 23:31:02 +02:00
|
|
|
++aSaveNd;
|
2000-09-18 23:08:29 +00:00
|
|
|
pDestRedl->GetMark()->nNode = aSaveNd;
|
|
|
|
pDestRedl->GetMark()->nContent.Assign( aSaveNd.GetNode().GetCntntNode(),
|
|
|
|
nSaveCnt );
|
|
|
|
|
2008-05-20 13:42:01 +00:00
|
|
|
if( GetPrev() != this )
|
|
|
|
{
|
|
|
|
SwPaM* pTmpPrev = ((_SaveMergeRedlines*)GetPrev())->pDestRedl;
|
|
|
|
if( pTmpPrev && *pTmpPrev->GetPoint() == *pDestRedl->GetPoint() )
|
|
|
|
*pTmpPrev->GetPoint() = *pDestRedl->GetMark();
|
|
|
|
}
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//JP 21.09.98: Bug 55909
|
2011-11-04 14:46:42 +01:00
|
|
|
// If there already is a deleted or inserted one at the same position, we have to split it!
|
2000-09-18 23:08:29 +00:00
|
|
|
SwPosition* pDStt = pDestRedl->GetMark(),
|
|
|
|
* pDEnd = pDestRedl->GetPoint();
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uInt16 n = 0;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// find the first redline for StartPos
|
2000-09-18 23:08:29 +00:00
|
|
|
if( !pDoc->GetRedline( *pDStt, &n ) && n )
|
|
|
|
--n;
|
|
|
|
|
|
|
|
const SwRedlineTbl& rRedlineTbl = pDoc->GetRedlineTbl();
|
2012-07-20 17:16:03 +02:00
|
|
|
for( ; n < rRedlineTbl.size(); ++n )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
SwRedline* pRedl = rRedlineTbl[ n ];
|
|
|
|
SwPosition* pRStt = pRedl->Start(),
|
|
|
|
* pREnd = pRStt == pRedl->GetPoint() ? pRedl->GetMark()
|
|
|
|
: pRedl->GetPoint();
|
2007-09-27 07:33:25 +00:00
|
|
|
if( nsRedlineType_t::REDLINE_DELETE == pRedl->GetType() ||
|
|
|
|
nsRedlineType_t::REDLINE_INSERT == pRedl->GetType() )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
SwComparePosition eCmpPos = ComparePosition( *pDStt, *pDEnd, *pRStt, *pREnd );
|
|
|
|
switch( eCmpPos )
|
|
|
|
{
|
2001-01-26 17:09:51 +00:00
|
|
|
case POS_COLLIDE_START:
|
2000-09-18 23:08:29 +00:00
|
|
|
case POS_BEHIND:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case POS_INSIDE:
|
|
|
|
case POS_EQUAL:
|
|
|
|
delete pDestRedl, pDestRedl = 0;
|
2011-11-04 14:46:42 +01:00
|
|
|
// break; -> no break !!!!
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2001-01-26 17:09:51 +00:00
|
|
|
case POS_COLLIDE_END:
|
2000-09-18 23:08:29 +00:00
|
|
|
case POS_BEFORE:
|
2012-07-20 17:16:03 +02:00
|
|
|
n = rRedlineTbl.size();
|
2000-09-18 23:08:29 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case POS_OUTSIDE:
|
|
|
|
{
|
|
|
|
SwRedline* pCpyRedl = new SwRedline(
|
|
|
|
pDestRedl->GetRedlineData(), *pDStt );
|
|
|
|
pCpyRedl->SetMark();
|
|
|
|
*pCpyRedl->GetPoint() = *pRStt;
|
|
|
|
|
2010-11-25 14:31:08 +01:00
|
|
|
SwUndoCompDoc *const pUndo =
|
|
|
|
(pDoc->GetIDocumentUndoRedo().DoesUndo())
|
2000-09-18 23:08:29 +00:00
|
|
|
? new SwUndoCompDoc( *pCpyRedl ) : 0;
|
2002-11-11 14:24:59 +00:00
|
|
|
|
|
|
|
// now modify doc: append redline, undo (and count)
|
2006-08-14 14:55:46 +00:00
|
|
|
pDoc->AppendRedline( pCpyRedl, true );
|
2002-11-11 14:24:59 +00:00
|
|
|
if( pUndo )
|
2010-11-25 14:31:08 +01:00
|
|
|
{
|
|
|
|
pDoc->GetIDocumentUndoRedo().AppendUndo(pUndo);
|
|
|
|
}
|
2002-11-11 14:24:59 +00:00
|
|
|
++nIns;
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
*pDStt = *pREnd;
|
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// we should start over now
|
2000-09-18 23:08:29 +00:00
|
|
|
n = USHRT_MAX;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case POS_OVERLAP_BEFORE:
|
|
|
|
*pDEnd = *pRStt;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case POS_OVERLAP_BEHIND:
|
|
|
|
*pDStt = *pREnd;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( *pDEnd <= *pRStt )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if( pDestRedl )
|
|
|
|
{
|
2010-11-25 14:31:08 +01:00
|
|
|
SwUndoCompDoc *const pUndo = (pDoc->GetIDocumentUndoRedo().DoesUndo())
|
|
|
|
? new SwUndoCompDoc( *pDestRedl ) : 0;
|
2002-11-11 14:24:59 +00:00
|
|
|
|
|
|
|
// now modify doc: append redline, undo (and count)
|
2006-08-14 14:55:46 +00:00
|
|
|
bool bRedlineAccepted = pDoc->AppendRedline( pDestRedl, true );
|
2002-11-11 14:24:59 +00:00
|
|
|
if( pUndo )
|
2010-11-25 14:31:08 +01:00
|
|
|
{
|
|
|
|
pDoc->GetIDocumentUndoRedo().AppendUndo( pUndo );
|
|
|
|
}
|
2002-11-11 14:24:59 +00:00
|
|
|
++nIns;
|
|
|
|
|
|
|
|
// if AppendRedline has deleted our redline, we may not keep a
|
|
|
|
// reference to it
|
|
|
|
if( ! bRedlineAccepted )
|
2002-11-11 10:45:45 +00:00
|
|
|
pDestRedl = NULL;
|
2000-09-18 23:08:29 +00:00
|
|
|
}
|
|
|
|
return nIns;
|
|
|
|
}
|
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// Merge two documents
|
2000-09-18 23:08:29 +00:00
|
|
|
long SwDoc::MergeDoc( const SwDoc& rDoc )
|
|
|
|
{
|
|
|
|
if( &rDoc == this )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
long nRet = 0;
|
|
|
|
|
2010-11-25 14:31:08 +01:00
|
|
|
GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
SwDoc& rSrcDoc = (SwDoc&)rDoc;
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_Bool bSrcModified = rSrcDoc.IsModified();
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2007-09-27 07:33:25 +00:00
|
|
|
RedlineMode_t eSrcRedlMode = rSrcDoc.GetRedlineMode();
|
|
|
|
rSrcDoc.SetRedlineMode( nsRedlineMode_t::REDLINE_SHOW_DELETE );
|
|
|
|
SetRedlineMode( nsRedlineMode_t::REDLINE_SHOW_DELETE );
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
SwCompareData aD0( rSrcDoc );
|
|
|
|
SwCompareData aD1( *this );
|
|
|
|
|
|
|
|
aD1.CompareLines( aD0 );
|
|
|
|
|
|
|
|
if( !aD1.HasDiffs( aD0 ) )
|
|
|
|
{
|
2011-11-04 14:46:42 +01:00
|
|
|
// we want to get all redlines from the SourceDoc
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// look for all insert redlines from the SourceDoc and determine their position in the DestDoc
|
2000-09-18 23:08:29 +00:00
|
|
|
_SaveMergeRedlines* pRing = 0;
|
|
|
|
const SwRedlineTbl& rSrcRedlTbl = rSrcDoc.GetRedlineTbl();
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nEndOfExtra = rSrcDoc.GetNodes().GetEndOfExtras().GetIndex();
|
|
|
|
sal_uLong nMyEndOfExtra = GetNodes().GetEndOfExtras().GetIndex();
|
2012-07-20 17:16:03 +02:00
|
|
|
for( sal_uInt16 n = 0; n < rSrcRedlTbl.size(); ++n )
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
const SwRedline* pRedl = rSrcRedlTbl[ n ];
|
2011-01-17 15:06:54 +01:00
|
|
|
sal_uLong nNd = pRedl->GetPoint()->nNode.GetIndex();
|
2007-09-27 07:33:25 +00:00
|
|
|
RedlineType_t eType = pRedl->GetType();
|
2000-09-18 23:08:29 +00:00
|
|
|
if( nEndOfExtra < nNd &&
|
2007-09-27 07:33:25 +00:00
|
|
|
( nsRedlineType_t::REDLINE_INSERT == eType || nsRedlineType_t::REDLINE_DELETE == eType ))
|
2000-09-18 23:08:29 +00:00
|
|
|
{
|
|
|
|
const SwNode* pDstNd = GetNodes()[
|
|
|
|
nMyEndOfExtra + nNd - nEndOfExtra ];
|
|
|
|
|
2011-11-04 14:46:42 +01:00
|
|
|
// Found the positon.
|
|
|
|
// Then we also have to insert the redline to the line in the DestDoc.
|
2000-09-18 23:08:29 +00:00
|
|
|
_SaveMergeRedlines* pTmp = new _SaveMergeRedlines(
|
|
|
|
*pDstNd, *pRedl, pRing );
|
|
|
|
if( !pRing )
|
|
|
|
pRing = pTmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( pRing )
|
|
|
|
{
|
2011-11-04 14:46:42 +01:00
|
|
|
// Carry over all into DestDoc
|
2007-09-27 07:33:25 +00:00
|
|
|
rSrcDoc.SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE));
|
2006-08-14 14:55:46 +00:00
|
|
|
|
2007-09-27 07:33:25 +00:00
|
|
|
SetRedlineMode((RedlineMode_t)(
|
|
|
|
nsRedlineMode_t::REDLINE_ON |
|
|
|
|
nsRedlineMode_t::REDLINE_SHOW_INSERT |
|
|
|
|
nsRedlineMode_t::REDLINE_SHOW_DELETE));
|
2006-08-14 14:55:46 +00:00
|
|
|
|
2000-09-18 23:08:29 +00:00
|
|
|
_SaveMergeRedlines* pTmp = pRing;
|
|
|
|
|
|
|
|
do {
|
2010-11-25 14:31:08 +01:00
|
|
|
nRet += pTmp->InsertRedline();
|
2000-09-18 23:08:29 +00:00
|
|
|
} while( pRing != ( pTmp = (_SaveMergeRedlines*)pTmp->GetNext() ));
|
|
|
|
|
|
|
|
while( pRing != pRing->GetNext() )
|
|
|
|
delete pRing->GetNext();
|
|
|
|
delete pRing;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rSrcDoc.SetRedlineMode( eSrcRedlMode );
|
|
|
|
if( !bSrcModified )
|
|
|
|
rSrcDoc.ResetModified();
|
|
|
|
|
2007-09-27 07:33:25 +00:00
|
|
|
SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE));
|
2000-09-18 23:08:29 +00:00
|
|
|
|
2010-11-25 14:31:08 +01:00
|
|
|
GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL);
|
2000-09-18 23:08:29 +00:00
|
|
|
|
|
|
|
return nRet;
|
|
|
|
}
|
2010-10-14 08:30:41 +02:00
|
|
|
|
2011-12-22 17:27:32 +01:00
|
|
|
LineArrayComparator::LineArrayComparator( const CompareData &rD1,
|
|
|
|
const CompareData &rD2, int nStt1,
|
|
|
|
int nEnd1, int nStt2, int nEnd2 )
|
|
|
|
: rData1( rD1 ), rData2( rD2 ), nFirst1( nStt1 ), nFirst2( nStt2 )
|
|
|
|
{
|
|
|
|
nLen1 = nEnd1 - nStt1;
|
|
|
|
nLen2 = nEnd2 - nStt2;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool LineArrayComparator::Compare( int nIdx1, int nIdx2 ) const
|
|
|
|
{
|
|
|
|
if( nIdx1 < 0 || nIdx2 < 0 || nIdx1 >= nLen1 || nIdx2 >= nLen2 )
|
|
|
|
{
|
|
|
|
OSL_ENSURE( 0, "Index out of range!" );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const SwTxtNode *pTxtNd1 = ( ( SwCompareLine* )rData1.GetLine( nFirst1 + nIdx1 ) )->GetNode().GetTxtNode();
|
|
|
|
const SwTxtNode *pTxtNd2 = ( ( SwCompareLine* )rData2.GetLine( nFirst2 + nIdx2 ) )->GetNode().GetTxtNode();
|
|
|
|
|
|
|
|
if( !pTxtNd1 || !pTxtNd2
|
|
|
|
|| ( CmpOptions.bUseRsid && !pTxtNd1->CompareParRsid( *pTxtNd2 ) ) )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nPar1Len = pTxtNd1->Len();
|
|
|
|
int nPar2Len = pTxtNd2->Len();
|
|
|
|
|
|
|
|
if( std::min( nPar1Len, nPar2Len ) * 3 < std::max( nPar1Len, nPar2Len ) )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nBorderLen = ( nPar1Len + nPar2Len )/16;
|
|
|
|
|
|
|
|
if( nBorderLen < 3 )
|
|
|
|
{
|
|
|
|
nBorderLen = std::min( 3, std::min( nPar1Len, nPar2Len ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
std::set<unsigned> aHashes;
|
|
|
|
unsigned nHash = 0;
|
|
|
|
unsigned nMul = 251;
|
|
|
|
unsigned nPow = 1;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for( i = 0; i < nBorderLen - 1; i++ )
|
|
|
|
{
|
|
|
|
nPow *= nMul;
|
|
|
|
}
|
|
|
|
for( i = 0; i < nBorderLen; i++ )
|
|
|
|
{
|
|
|
|
nHash = nHash*nMul + pTxtNd1->GetTxt().GetChar( i );
|
|
|
|
}
|
|
|
|
aHashes.insert( nHash );
|
|
|
|
for( ; i < nPar1Len; i++ )
|
|
|
|
{
|
|
|
|
nHash = nHash - nPow*pTxtNd1->GetTxt().GetChar( i - nBorderLen );
|
|
|
|
nHash = nHash*nMul + pTxtNd1->GetTxt().GetChar( i );
|
|
|
|
|
|
|
|
aHashes.insert( nHash );
|
|
|
|
}
|
|
|
|
|
|
|
|
nHash = 0;
|
|
|
|
for( i = 0; i < nBorderLen; i++ )
|
|
|
|
{
|
|
|
|
nHash = nHash*nMul + pTxtNd2->GetTxt().GetChar( i );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( aHashes.find( nHash ) != aHashes.end() )
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for( ; i < nPar2Len; i++ )
|
|
|
|
{
|
|
|
|
nHash = nHash - nPow*pTxtNd2->GetTxt().GetChar( i - nBorderLen );
|
|
|
|
nHash = nHash*nMul + pTxtNd2->GetTxt().GetChar( i );
|
|
|
|
if( aHashes.find( nHash ) != aHashes.end() )
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CharArrayComparator::Compare( int nIdx1, int nIdx2 ) const
|
|
|
|
{
|
|
|
|
if( nIdx1 < 0 || nIdx2 < 0 || nIdx1 >= GetLen1() || nIdx2 >= GetLen2() )
|
|
|
|
{
|
|
|
|
OSL_ENSURE( 0, "Index out of range!" );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ( !CmpOptions.bUseRsid
|
|
|
|
|| pTxtNd1->CompareRsid( *pTxtNd2, nIdx1 + 1, nIdx2 + 1 ) )
|
|
|
|
&& pTxtNd1->GetTxt().GetChar( nIdx1 )
|
|
|
|
== pTxtNd2->GetTxt().GetChar( nIdx2 );
|
|
|
|
}
|
|
|
|
|
|
|
|
WordArrayComparator::WordArrayComparator( const SwTxtNode *pNode1,
|
|
|
|
const SwTxtNode *pNode2 )
|
2012-09-11 11:25:20 +02:00
|
|
|
: pTxtNd1( pNode1 ), pTxtNd2( pNode2 )
|
2011-12-22 17:27:32 +01:00
|
|
|
{
|
|
|
|
pPos1 = new int[ pTxtNd1->GetTxt().Len() + 1 ];
|
|
|
|
pPos2 = new int[ pTxtNd2->GetTxt().Len() + 1 ];
|
|
|
|
|
|
|
|
CalcPositions( pPos1, pTxtNd1, nCnt1 );
|
|
|
|
CalcPositions( pPos2, pTxtNd2, nCnt2 );
|
|
|
|
}
|
|
|
|
|
|
|
|
WordArrayComparator::~WordArrayComparator()
|
|
|
|
{
|
|
|
|
delete[] pPos1;
|
|
|
|
delete[] pPos2;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WordArrayComparator::Compare( int nIdx1, int nIdx2 ) const
|
|
|
|
{
|
|
|
|
int nLen = pPos1[ nIdx1 + 1 ] - pPos1[ nIdx1 ];
|
|
|
|
if( nLen != pPos2[ nIdx2 + 1 ] - pPos2[ nIdx2 ] )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for( int i = 0; i < nLen; i++)
|
|
|
|
{
|
|
|
|
if( pTxtNd1->GetTxt().GetChar( pPos1[ nIdx1 ] + i )
|
|
|
|
!= pTxtNd2->GetTxt().GetChar( pPos2[ nIdx2 ] + i )
|
|
|
|
|| ( CmpOptions.bUseRsid && !pTxtNd1->CompareRsid( *pTxtNd2,
|
|
|
|
pPos1[ nIdx1 ] + i, pPos2[ nIdx2 ] + i ) ) )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int WordArrayComparator::GetCharSequence( const int *pWordLcs1,
|
|
|
|
const int *pWordLcs2, int *pSubseq1, int *pSubseq2, int nLcsLen )
|
|
|
|
{
|
|
|
|
int nLen = 0;
|
|
|
|
for( int i = 0; i < nLcsLen; i++ )
|
|
|
|
{
|
|
|
|
// Check for hash collisions
|
|
|
|
if( pPos1[ pWordLcs1[i] + 1 ] - pPos1[ pWordLcs1[i] ]
|
|
|
|
!= pPos2[ pWordLcs2[i] + 1 ] - pPos2[ pWordLcs2[i] ] )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for( int j = 0; j < pPos1[pWordLcs1[i]+1] - pPos1[pWordLcs1[i]]; j++)
|
|
|
|
{
|
|
|
|
pSubseq1[ nLen ] = pPos1[ pWordLcs1[i] ] + j;
|
|
|
|
pSubseq2[ nLen ] = pPos2[ pWordLcs2[i] ] + j;
|
|
|
|
|
|
|
|
if( pTxtNd1->GetTxt().GetChar( pPos1[ pWordLcs1[i] ] + j )
|
|
|
|
!= pTxtNd2->GetTxt().GetChar( pPos2[ pWordLcs2[i] ] + j ) )
|
|
|
|
{
|
|
|
|
nLen -= j;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
nLen++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nLen;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WordArrayComparator::CalcPositions( int *pPos, const SwTxtNode *pTxtNd,
|
|
|
|
int &nCnt )
|
|
|
|
{
|
|
|
|
nCnt = -1;
|
|
|
|
for( int i = 0; i <= pTxtNd->GetTxt().Len(); i++ )
|
|
|
|
{
|
|
|
|
if( i == 0 || i == pTxtNd->GetTxt().Len()
|
|
|
|
|| !isalnum( pTxtNd->GetTxt().GetChar( i - 1 ) )
|
|
|
|
|| !isalnum( pTxtNd->GetTxt().GetChar( i ) ) )
|
|
|
|
{ // Begin new word
|
|
|
|
nCnt++;
|
|
|
|
pPos[ nCnt ] = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CommonSubseq::FindLCS( int *pLcs1, int *pLcs2, int nStt1, int nEnd1,
|
|
|
|
int nStt2, int nEnd2 )
|
|
|
|
{
|
|
|
|
int nLen1 = nEnd1 ? nEnd1 - nStt1 : rCmp.GetLen1();
|
|
|
|
int nLen2 = nEnd2 ? nEnd2 - nStt2 : rCmp.GetLen2();
|
|
|
|
|
|
|
|
OSL_ASSERT( nLen1 >= 0 );
|
|
|
|
OSL_ASSERT( nLen2 >= 0 );
|
|
|
|
|
|
|
|
int **pLcs = new int*[ nLen1 + 1 ];
|
|
|
|
pLcs[ 0 ] = pData;
|
|
|
|
|
|
|
|
for( int i = 1; i < nLen1 + 1; i++ )
|
|
|
|
pLcs[ i ] = pLcs[ i - 1 ] + nLen2 + 1;
|
|
|
|
|
|
|
|
for( int i = 0; i <= nLen1; i++ )
|
|
|
|
pLcs[i][0] = 0;
|
|
|
|
|
|
|
|
for( int j = 0; j <= nLen2; j++ )
|
|
|
|
pLcs[0][j] = 0;
|
|
|
|
|
|
|
|
// Find lcs
|
|
|
|
for( int i = 1; i <= nLen1; i++ )
|
|
|
|
{
|
|
|
|
for( int j = 1; j <= nLen2; j++ )
|
|
|
|
{
|
|
|
|
if( rCmp.Compare( nStt1 + i - 1, nStt2 + j - 1 ) )
|
|
|
|
pLcs[i][j] = pLcs[i - 1][j - 1] + 1;
|
|
|
|
else
|
|
|
|
pLcs[i][j] = std::max( pLcs[i][j - 1], pLcs[i - 1][j] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int nLcsLen = pLcs[ nLen1 ][ nLen2 ];
|
|
|
|
|
|
|
|
// Recover the lcs in the two sequences
|
|
|
|
if( pLcs1 && pLcs2 )
|
|
|
|
{
|
|
|
|
int nIdx1 = nLen1;
|
|
|
|
int nIdx2 = nLen2;
|
|
|
|
int nIdx = nLcsLen - 1;
|
|
|
|
|
|
|
|
while( nIdx1 > 0 && nIdx2 > 0 )
|
|
|
|
{
|
|
|
|
if( pLcs[ nIdx1 ][ nIdx2 ] == pLcs[ nIdx1 - 1 ][ nIdx2 ] )
|
|
|
|
nIdx1--;
|
|
|
|
else if( pLcs[ nIdx1 ][ nIdx2 ] == pLcs[ nIdx1 ][ nIdx2 - 1 ] )
|
|
|
|
nIdx2--;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nIdx1--, nIdx2--;
|
|
|
|
pLcs1[ nIdx ] = nIdx1 + nStt1;
|
|
|
|
pLcs2[ nIdx ] = nIdx2 + nStt2;
|
|
|
|
nIdx--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] pLcs;
|
|
|
|
|
|
|
|
return nLcsLen;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CommonSubseq::IgnoreIsolatedPieces( int *pLcs1, int *pLcs2, int nLen1,
|
|
|
|
int nLen2, int nLcsLen, int nPieceLen )
|
|
|
|
{
|
|
|
|
if( !nLcsLen )
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nNext = 0;
|
|
|
|
|
|
|
|
// Don't ignore text at the beginning of the paragraphs
|
|
|
|
if( pLcs1[ 0 ] == 0 && pLcs2[ 0 ] == 0 )
|
|
|
|
{
|
|
|
|
while( nNext < nLcsLen - 1 && pLcs1[ nNext ] + 1 == pLcs1[ nNext + 1 ]
|
|
|
|
&& pLcs2[ nNext ] + 1 == pLcs2[ nNext + 1 ] )
|
|
|
|
{
|
|
|
|
nNext++;
|
|
|
|
}
|
|
|
|
nNext++;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nCnt = 1;
|
|
|
|
|
|
|
|
for( int i = nNext; i < nLcsLen; i++ )
|
|
|
|
{
|
|
|
|
if( i != nLcsLen - 1 && pLcs1[ i ] + 1 == pLcs1[ i + 1 ]
|
|
|
|
&& pLcs2[ i ] + 1 == pLcs2[ i + 1 ] )
|
|
|
|
{
|
|
|
|
nCnt++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( nCnt > nPieceLen
|
|
|
|
// Don't ignore text at the end of the paragraphs
|
|
|
|
|| ( i == nLcsLen - 1
|
|
|
|
&& pLcs1[i] == nLen1 - 1 && pLcs2[i] == nLen2 - 1 ))
|
|
|
|
{
|
|
|
|
for( int j = i + 1 - nCnt; j <= i; j++ )
|
|
|
|
{
|
|
|
|
pLcs2[ nNext ] = pLcs2[ j ];
|
|
|
|
pLcs1[ nNext ] = pLcs1[ j ];
|
|
|
|
nNext++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nCnt = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
LgstCommonSubseq::LgstCommonSubseq( ArrayComparator &rComparator )
|
|
|
|
: CommonSubseq( rComparator, CUTOFF )
|
|
|
|
{
|
|
|
|
pBuff1 = new int[ rComparator.GetLen2() + 1 ];
|
|
|
|
pBuff2 = new int[ rComparator.GetLen2() + 1 ];
|
|
|
|
|
|
|
|
pL1 = new int[ rComparator.GetLen2() + 1 ];
|
|
|
|
pL2 = new int[ rComparator.GetLen2() + 1 ];
|
|
|
|
}
|
|
|
|
|
|
|
|
LgstCommonSubseq::~LgstCommonSubseq()
|
|
|
|
{
|
|
|
|
delete[] pBuff1;
|
|
|
|
delete[] pBuff2;
|
|
|
|
|
|
|
|
delete[] pL1;
|
|
|
|
delete[] pL2;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LgstCommonSubseq::FindL( int *pL, int nStt1, int nEnd1,
|
|
|
|
int nStt2, int nEnd2 )
|
|
|
|
{
|
|
|
|
int nLen1 = nEnd1 ? nEnd1 - nStt1 : rCmp.GetLen1();
|
|
|
|
int nLen2 = nEnd2 ? nEnd2 - nStt2 : rCmp.GetLen2();
|
|
|
|
|
|
|
|
int *currL = pBuff1;
|
|
|
|
int *prevL = pBuff2;
|
|
|
|
|
|
|
|
// Avoid memory corruption
|
|
|
|
if( nLen2 > rCmp.GetLen2() )
|
|
|
|
{
|
|
|
|
assert( false );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset( pBuff1, 0, sizeof( *pBuff1 ) * ( nLen2 + 1 ) );
|
|
|
|
memset( pBuff2, 0, sizeof( *pBuff2 ) * ( nLen2 + 1 ) );
|
|
|
|
|
|
|
|
// Find lcs
|
|
|
|
for( int i = 1; i <= nLen1; i++ )
|
|
|
|
{
|
|
|
|
for( int j = 1; j <= nLen2; j++ )
|
|
|
|
{
|
|
|
|
if( rCmp.Compare( nStt1 + i - 1, nStt2 + j - 1 ) )
|
|
|
|
currL[j] = prevL[j - 1] + 1;
|
|
|
|
else
|
|
|
|
currL[j] = std::max( currL[j - 1], prevL[j] );
|
|
|
|
}
|
|
|
|
int *tmp = currL;
|
|
|
|
currL = prevL;
|
|
|
|
prevL = tmp;
|
|
|
|
}
|
|
|
|
memcpy( pL, prevL, ( nLen2 + 1 ) * sizeof( *prevL ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
int LgstCommonSubseq::HirschbergLCS( int *pLcs1, int *pLcs2, int nStt1,
|
|
|
|
int nEnd1, int nStt2, int nEnd2 )
|
|
|
|
{
|
|
|
|
static int nLen1;
|
|
|
|
static int nLen2;
|
|
|
|
nLen1 = nEnd1 - nStt1;
|
|
|
|
nLen2 = nEnd2 - nStt2;
|
|
|
|
|
|
|
|
if( ( nLen1 + 1 ) * ( nLen2 + 1 ) <= CUTOFF )
|
|
|
|
{
|
|
|
|
if( !nLen1 || !nLen2 )
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return FindLCS(pLcs1, pLcs2, nStt1, nEnd1, nStt2, nEnd2);
|
|
|
|
}
|
|
|
|
|
|
|
|
int nMid = nLen1/2;
|
|
|
|
|
|
|
|
FindL( pL1, nStt1, nStt1 + nMid, nStt2, nEnd2 );
|
|
|
|
FindL( pL2, nStt1 + nMid, nEnd1, nStt2, nEnd2 );
|
|
|
|
|
|
|
|
int nMaxPos = 0;
|
|
|
|
static int nMaxVal;
|
|
|
|
nMaxVal = -1;
|
|
|
|
|
|
|
|
static int i;
|
|
|
|
for( i = 0; i <= nLen2; i++ )
|
|
|
|
{
|
|
|
|
if( pL1[i] + ( pL2[nLen2] - pL2[i] ) > nMaxVal )
|
|
|
|
{
|
|
|
|
nMaxPos = i;
|
|
|
|
nMaxVal = pL1[i]+( pL2[nLen2] - pL2[i] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int nRet = HirschbergLCS( pLcs1, pLcs2, nStt1, nStt1 + nMid,
|
|
|
|
nStt2, nStt2 + nMaxPos );
|
|
|
|
nRet += HirschbergLCS( pLcs1 + nRet, pLcs2 + nRet, nStt1 + nMid, nEnd1,
|
|
|
|
nStt2 + nMaxPos, nEnd2 );
|
|
|
|
|
|
|
|
return nRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
int LgstCommonSubseq::Find( int *pSubseq1, int *pSubseq2 )
|
|
|
|
{
|
|
|
|
int nStt = 0;
|
|
|
|
int nCutEnd = 0;
|
|
|
|
int nEnd1 = rCmp.GetLen1();
|
|
|
|
int nEnd2 = rCmp.GetLen2();
|
|
|
|
|
|
|
|
// Check for corresponding lines in the beginning of the sequences
|
|
|
|
while( nStt < nEnd1 && nStt < nEnd2 && rCmp.Compare( nStt, nStt ) )
|
|
|
|
{
|
|
|
|
pSubseq1[ nStt ] = nStt;
|
|
|
|
pSubseq2[ nStt ] = nStt;
|
|
|
|
nStt++;
|
|
|
|
}
|
|
|
|
|
|
|
|
pSubseq1 += nStt;
|
|
|
|
pSubseq2 += nStt;
|
|
|
|
|
|
|
|
// Check for corresponding lines in the end of the sequences
|
|
|
|
while( nStt < nEnd1 && nStt < nEnd2
|
|
|
|
&& rCmp.Compare( nEnd1 - 1, nEnd2 - 1 ) )
|
|
|
|
{
|
|
|
|
nCutEnd++;
|
|
|
|
nEnd1--;
|
|
|
|
nEnd2--;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nLen = HirschbergLCS( pSubseq1, pSubseq2, nStt, nEnd1, nStt, nEnd2 );
|
|
|
|
|
|
|
|
for( int i = 0; i < nCutEnd; i++ )
|
|
|
|
{
|
|
|
|
pSubseq1[ nLen + i ] = nEnd1 + i;
|
|
|
|
pSubseq2[ nLen + i ] = nEnd2 + i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nStt + nLen + nCutEnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
int FastCommonSubseq::FindFastCS( int *pSeq1, int *pSeq2, int nStt1,
|
|
|
|
int nEnd1, int nStt2, int nEnd2 )
|
|
|
|
{
|
|
|
|
int nCutBeg = 0;
|
|
|
|
int nCutEnd = 0;
|
|
|
|
|
|
|
|
// Check for corresponding lines in the beginning of the sequences
|
|
|
|
while( nStt1 < nEnd1 && nStt2 < nEnd2 && rCmp.Compare( nStt1, nStt2 ) )
|
|
|
|
{
|
|
|
|
pSeq1[ nCutBeg ] = nStt1++;
|
|
|
|
pSeq2[ nCutBeg ] = nStt2++;
|
|
|
|
nCutBeg++;
|
|
|
|
}
|
|
|
|
|
|
|
|
pSeq1 += nCutBeg;
|
|
|
|
pSeq2 += nCutBeg;
|
|
|
|
|
|
|
|
// Check for corresponding lines in the end of the sequences
|
|
|
|
while( nStt1 < nEnd1 && nStt2 < nEnd2
|
|
|
|
&& rCmp.Compare( nEnd1 - 1, nEnd2 - 1 ) )
|
|
|
|
{
|
|
|
|
nCutEnd++;
|
|
|
|
nEnd1--;
|
|
|
|
nEnd2--;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nLen1 = nEnd1 - nStt1;
|
|
|
|
int nLen2 = nEnd2 - nStt2;
|
|
|
|
|
|
|
|
// Return if a sequence is empty
|
|
|
|
if( nLen1 <= 0 || nLen2 <= 0 )
|
|
|
|
{
|
|
|
|
for( int i = 0; i < nCutEnd; i++ )
|
|
|
|
{
|
|
|
|
pSeq1[ i ] = nEnd1 + i;
|
|
|
|
pSeq2[ i ] = nEnd2 + i;
|
|
|
|
}
|
|
|
|
return nCutBeg + nCutEnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cut to LCS for small values
|
|
|
|
if( nLen1 < 3 || nLen2 < 3 || ( nLen1 + 1 ) * ( nLen2 + 1 ) <= CUTOFF )
|
|
|
|
{
|
|
|
|
int nLcsLen = FindLCS( pSeq1, pSeq2, nStt1, nEnd1, nStt2, nEnd2);
|
|
|
|
|
|
|
|
for( int i = 0; i < nCutEnd; i++ )
|
|
|
|
{
|
|
|
|
pSeq1[ nLcsLen + i ] = nEnd1 + i;
|
|
|
|
pSeq2[ nLcsLen + i ] = nEnd2 + i;
|
|
|
|
}
|
|
|
|
return nCutBeg + nLcsLen + nCutEnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nMid1 = nLen1/2;
|
|
|
|
int nMid2 = nLen2/2;
|
|
|
|
|
|
|
|
int nRad;
|
|
|
|
int nPos1 = -1, nPos2 = -1;
|
|
|
|
|
|
|
|
// Find a point of correspondence in the middle of the sequences
|
|
|
|
for( nRad = 0; nRad*nRad < std::min( nMid1, nMid2 ); nRad++ )
|
|
|
|
{
|
|
|
|
// Search to the left and to the right of the middle of the first sequence
|
|
|
|
for( int i = nMid1 - nRad; i <= nMid1 + nRad; i++ )
|
|
|
|
{
|
|
|
|
if( rCmp.Compare( nStt1 + i, nStt2 + nMid2 - nRad ) )
|
|
|
|
{
|
|
|
|
nPos1 = nStt1 + i;
|
|
|
|
nPos2 = nStt2 + nMid2 - nRad;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if( rCmp.Compare( nStt1 + i, nStt2 + nMid2 + nRad ) )
|
|
|
|
{
|
|
|
|
nPos1 = nStt1 + i;
|
|
|
|
nPos2 = nStt2 + nMid2 - nRad;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Search to the left and to the right of the middle of the second sequence
|
|
|
|
for( int i = nMid2 - nRad; i <= nMid2 + nRad; i++ )
|
|
|
|
{
|
|
|
|
if( rCmp.Compare( nStt2 + nMid2 - nRad, nStt2 + i ) )
|
|
|
|
{
|
|
|
|
nPos2 = nStt2 + i;
|
|
|
|
nPos1 = nStt1 + nMid1 - nRad;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if( rCmp.Compare( nStt2 + nMid2 - nRad, nStt2 + i ) )
|
|
|
|
{
|
|
|
|
nPos2 = nStt2 + i;
|
|
|
|
nPos1 = nStt1 + nMid1 - nRad;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// return if no point of correspondence found
|
|
|
|
if( nPos1 == -1 )
|
|
|
|
{
|
|
|
|
for( int i = 0; i < nCutEnd; i++ )
|
|
|
|
{
|
|
|
|
pSeq1[ i ] = nEnd1 + i;
|
|
|
|
pSeq2[ i ] = nEnd2 + i;
|
|
|
|
}
|
|
|
|
return nCutBeg + nCutEnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run the same on the sequences to the left of the correspondence point
|
|
|
|
int nLen = FindFastCS( pSeq1, pSeq2, nStt1, nPos1, nStt2, nPos2 );
|
|
|
|
|
|
|
|
pSeq1[ nLen ] = nPos1;
|
|
|
|
pSeq2[ nLen ] = nPos2;
|
|
|
|
|
|
|
|
// Run the same on the sequences to the right of the correspondence point
|
|
|
|
nLen += FindFastCS( pSeq1 + nLen + 1, pSeq2 + nLen + 1,
|
|
|
|
nPos1 + 1, nEnd1, nPos2 + 1, nEnd2 ) + 1;
|
|
|
|
|
|
|
|
for( int i = 0; i < nCutEnd; i++ )
|
|
|
|
{
|
|
|
|
pSeq1[ nLen + i ] = nEnd1 + i;
|
|
|
|
pSeq2[ nLen + i ] = nEnd2 + i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nLen + nCutBeg + nCutEnd;
|
|
|
|
}
|
|
|
|
|
2010-10-14 08:30:41 +02:00
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|