|
|
|
/***************************************************************************
|
|
|
|
diff.h - description
|
|
|
|
-------------------
|
|
|
|
begin : Mon Mar 18 2002
|
|
|
|
copyright : (C) 2002-2007 by Joachim Eibl
|
|
|
|
email : joachim.eibl at gmx.de
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#ifndef DIFF_H
|
|
|
|
#define DIFF_H
|
|
|
|
|
|
|
|
#include <tqwidget.h>
|
|
|
|
#include <tqpixmap.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <tqframe.h>
|
|
|
|
#include <textstream.h>
|
|
|
|
#include <tqpainter.h>
|
|
|
|
#include <list>
|
|
|
|
#include <vector>
|
|
|
|
#include <assert.h>
|
|
|
|
#include "common.h"
|
|
|
|
#include "fileaccess.h"
|
|
|
|
|
|
|
|
class OptionDialog;
|
|
|
|
|
|
|
|
// Each range with matching elements is followed by a range with differences on either side.
|
|
|
|
// Then again range of matching elements should follow.
|
|
|
|
struct Diff
|
|
|
|
{
|
|
|
|
int nofEquals;
|
|
|
|
|
|
|
|
int diff1;
|
|
|
|
int diff2;
|
|
|
|
|
|
|
|
Diff(int eq, int d1, int d2){nofEquals=eq; diff1=d1; diff2=d2; }
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::list<Diff> DiffList;
|
|
|
|
|
|
|
|
struct LineData
|
|
|
|
{
|
|
|
|
const TQChar* pLine;
|
|
|
|
const TQChar* pFirstNonWhiteChar;
|
|
|
|
int size;
|
|
|
|
|
|
|
|
LineData(){ pLine=0; pFirstNonWhiteChar=0; size=0; /*occurances=0;*/ bContainsPureComment=false; }
|
|
|
|
int width(int tabSize) const; // Calcs width considering tabs.
|
|
|
|
//int occurances;
|
|
|
|
bool whiteLine() const { return pFirstNonWhiteChar-pLine == size; }
|
|
|
|
bool bContainsPureComment;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Diff3LineList;
|
|
|
|
class Diff3LineVector;
|
|
|
|
|
|
|
|
struct DiffBufferInfo
|
|
|
|
{
|
|
|
|
const LineData* m_pLineDataA;
|
|
|
|
const LineData* m_pLineDataB;
|
|
|
|
const LineData* m_pLineDataC;
|
|
|
|
int m_sizeA;
|
|
|
|
int m_sizeB;
|
|
|
|
int m_sizeC;
|
|
|
|
const Diff3LineList* m_pDiff3LineList;
|
|
|
|
const Diff3LineVector* m_pDiff3LineVector;
|
|
|
|
void init( Diff3LineList* d3ll, const Diff3LineVector* d3lv,
|
|
|
|
const LineData* pldA, int sizeA, const LineData* pldB, int sizeB, const LineData* pldC, int sizeC );
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Diff3Line
|
|
|
|
{
|
|
|
|
int lineA;
|
|
|
|
int lineB;
|
|
|
|
int lineC;
|
|
|
|
|
|
|
|
bool bAEqC : 1; // These are true if equal or only white-space changes exist.
|
|
|
|
bool bBEqC : 1;
|
|
|
|
bool bAEqB : 1;
|
|
|
|
|
|
|
|
bool bWhiteLineA : 1;
|
|
|
|
bool bWhiteLineB : 1;
|
|
|
|
bool bWhiteLineC : 1;
|
|
|
|
|
|
|
|
DiffList* pFineAB; // These are 0 only if completely equal or if either source doesn't exist.
|
|
|
|
DiffList* pFineBC;
|
|
|
|
DiffList* pFineCA;
|
|
|
|
|
|
|
|
int linesNeededForDisplay; // Due to wordwrap
|
|
|
|
int sumLinesNeededForDisplay; // For fast conversion to m_diff3WrapLineVector
|
|
|
|
|
|
|
|
DiffBufferInfo* m_pDiffBufferInfo; // For convenience
|
|
|
|
|
|
|
|
Diff3Line()
|
|
|
|
{
|
|
|
|
lineA=-1; lineB=-1; lineC=-1;
|
|
|
|
bAEqC=false; bAEqB=false; bBEqC=false;
|
|
|
|
pFineAB=0; pFineBC=0; pFineCA=0;
|
|
|
|
linesNeededForDisplay=1;
|
|
|
|
sumLinesNeededForDisplay=0;
|
|
|
|
bWhiteLineA=false; bWhiteLineB=false; bWhiteLineC=false;
|
|
|
|
m_pDiffBufferInfo=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
~Diff3Line()
|
|
|
|
{
|
|
|
|
if (pFineAB!=0) delete pFineAB;
|
|
|
|
if (pFineBC!=0) delete pFineBC;
|
|
|
|
if (pFineCA!=0) delete pFineCA;
|
|
|
|
pFineAB=0; pFineBC=0; pFineCA=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator==( const Diff3Line& d3l )
|
|
|
|
{
|
|
|
|
return lineA == d3l.lineA && lineB == d3l.lineB && lineC == d3l.lineC
|
|
|
|
&& bAEqB == d3l.bAEqB && bAEqC == d3l.bAEqC && bBEqC == d3l.bBEqC;
|
|
|
|
}
|
|
|
|
|
|
|
|
const LineData* getLineData( int src ) const
|
|
|
|
{
|
|
|
|
assert( m_pDiffBufferInfo!=0 );
|
|
|
|
if ( src == 1 && lineA >= 0 ) return &m_pDiffBufferInfo->m_pLineDataA[lineA];
|
|
|
|
if ( src == 2 && lineB >= 0 ) return &m_pDiffBufferInfo->m_pLineDataB[lineB];
|
|
|
|
if ( src == 3 && lineC >= 0 ) return &m_pDiffBufferInfo->m_pLineDataC[lineC];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
TQString getString( int src ) const
|
|
|
|
{
|
|
|
|
const LineData* pld = getLineData(src);
|
|
|
|
if ( pld )
|
|
|
|
return TQString( pld->pLine, pld->size);
|
|
|
|
else
|
|
|
|
return TQString();
|
|
|
|
}
|
|
|
|
int getLineInFile( int src ) const
|
|
|
|
{
|
|
|
|
if ( src == 1 ) return lineA;
|
|
|
|
if ( src == 2 ) return lineB;
|
|
|
|
if ( src == 3 ) return lineC;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class Diff3LineList : public std::list<Diff3Line>
|
|
|
|
{
|
|
|
|
};
|
|
|
|
class Diff3LineVector : public std::vector<Diff3Line*>
|
|
|
|
{
|
|
|
|
};
|
|
|
|
|
|
|
|
class Diff3WrapLine
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Diff3Line* pD3L;
|
|
|
|
int diff3LineIndex;
|
|
|
|
int wrapLineOffset;
|
|
|
|
int wrapLineLength;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::vector<Diff3WrapLine> Diff3WrapLineVector;
|
|
|
|
|
|
|
|
|
|
|
|
class TotalDiffStatus
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
TotalDiffStatus(){ reset(); }
|
|
|
|
void reset() {bBinaryAEqC=false; bBinaryBEqC=false; bBinaryAEqB=false;
|
|
|
|
bTextAEqC=false; bTextBEqC=false; bTextAEqB=false;
|
|
|
|
nofUnsolvedConflicts=0; nofSolvedConflicts=0;
|
|
|
|
nofWhitespaceConflicts=0;
|
|
|
|
}
|
|
|
|
bool bBinaryAEqC;
|
|
|
|
bool bBinaryBEqC;
|
|
|
|
bool bBinaryAEqB;
|
|
|
|
|
|
|
|
bool bTextAEqC;
|
|
|
|
bool bTextBEqC;
|
|
|
|
bool bTextAEqB;
|
|
|
|
|
|
|
|
int nofUnsolvedConflicts;
|
|
|
|
int nofSolvedConflicts;
|
|
|
|
int nofWhitespaceConflicts;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Three corresponding ranges. (Minimum size of a valid range is one line.)
|
|
|
|
class ManualDiffHelpEntry
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ManualDiffHelpEntry() { lineA1=-1; lineA2=-1;
|
|
|
|
lineB1=-1; lineB2=-1;
|
|
|
|
lineC1=-1; lineC2=-1; }
|
|
|
|
int lineA1;
|
|
|
|
int lineA2;
|
|
|
|
int lineB1;
|
|
|
|
int lineB2;
|
|
|
|
int lineC1;
|
|
|
|
int lineC2;
|
|
|
|
int& firstLine( int winIdx )
|
|
|
|
{
|
|
|
|
return winIdx==1 ? lineA1 : (winIdx==2 ? lineB1 : lineC1 );
|
|
|
|
}
|
|
|
|
int& lastLine( int winIdx )
|
|
|
|
{
|
|
|
|
return winIdx==1 ? lineA2 : (winIdx==2 ? lineB2 : lineC2 );
|
|
|
|
}
|
|
|
|
bool isLineInRange( int line, int winIdx )
|
|
|
|
{
|
|
|
|
return line>=0 && line>=firstLine(winIdx) && line<=lastLine(winIdx);
|
|
|
|
}
|
|
|
|
bool operator==(const ManualDiffHelpEntry& r) const
|
|
|
|
{
|
|
|
|
return lineA1 == r.lineA1 && lineB1 == r.lineB1 && lineC1 == r.lineC1 &&
|
|
|
|
lineA2 == r.lineA2 && lineB2 == r.lineB2 && lineC2 == r.lineC2;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// A list of corresponding ranges
|
|
|
|
typedef std::list<ManualDiffHelpEntry> ManualDiffHelpList;
|
|
|
|
|
|
|
|
void calcDiff3LineListUsingAB(
|
|
|
|
const DiffList* pDiffListAB,
|
|
|
|
Diff3LineList& d3ll
|
|
|
|
);
|
|
|
|
|
|
|
|
void calcDiff3LineListUsingAC(
|
|
|
|
const DiffList* pDiffListBC,
|
|
|
|
Diff3LineList& d3ll
|
|
|
|
);
|
|
|
|
|
|
|
|
void calcDiff3LineListUsingBC(
|
|
|
|
const DiffList* pDiffListBC,
|
|
|
|
Diff3LineList& d3ll
|
|
|
|
);
|
|
|
|
|
|
|
|
void correctManualDiffAlignment( Diff3LineList& d3ll, ManualDiffHelpList* pManualDiffHelpList );
|
|
|
|
|
|
|
|
class SourceData
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
SourceData();
|
|
|
|
~SourceData();
|
|
|
|
|
|
|
|
void setOptionDialog( OptionDialog* pOptionDialog );
|
|
|
|
|
|
|
|
int getSizeLines() const;
|
|
|
|
int getSizeBytes() const;
|
|
|
|
const char* getBuf() const;
|
|
|
|
const LineData* getLineDataForDisplay() const;
|
|
|
|
const LineData* getLineDataForDiff() const;
|
|
|
|
|
|
|
|
void setFilename(const TQString& filename);
|
|
|
|
void setFileAccess( const FileAccess& fa );
|
|
|
|
//FileAccess& getFileAccess();
|
|
|
|
TQString getFilename();
|
|
|
|
void setAliasName(const TQString& a);
|
|
|
|
TQString getAliasName();
|
|
|
|
bool isEmpty(); // File was set
|
|
|
|
bool hasData(); // Data was readable
|
|
|
|
bool isText(); // is it pure text (vs. binary data)
|
|
|
|
bool isFromBuffer(); // was it set via setData() (vs. setFileAccess() or setFilename())
|
|
|
|
void setData( const TQString& data );
|
|
|
|
bool isValid(); // Either no file is specified or reading was successful
|
|
|
|
|
|
|
|
void readAndPreprocess(TQTextCodec* pEncoding, bool bAutoDetectUnicode );
|
|
|
|
bool saveNormalDataAs( const TQString& fileName );
|
|
|
|
|
|
|
|
bool isBinaryEqualWith( const SourceData& other ) const;
|
|
|
|
|
|
|
|
void reset();
|
|
|
|
|
|
|
|
TQTextCodec* getEncoding() const { return m_pEncoding; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
TQTextCodec* detectEncoding( const TQString& fileName, TQTextCodec* pFallbackCodec );
|
|
|
|
TQString m_aliasName;
|
|
|
|
FileAccess m_fileAccess;
|
|
|
|
OptionDialog* m_pOptionDialog;
|
|
|
|
TQString m_tempInputFileName;
|
|
|
|
|
|
|
|
struct FileData
|
|
|
|
{
|
|
|
|
FileData(){ m_pBuf=0; m_size=0; m_vSize=0; m_bIsText=false; }
|
|
|
|
~FileData(){ reset(); }
|
|
|
|
const char* m_pBuf;
|
|
|
|
int m_size;
|
|
|
|
int m_vSize; // Nr of lines in m_pBuf1 and size of m_v1, m_dv12 and m_dv13
|
|
|
|
TQString m_unicodeBuf;
|
|
|
|
std::vector<LineData> m_v;
|
|
|
|
bool m_bIsText;
|
|
|
|
bool readFile( const TQString& filename );
|
|
|
|
bool writeFile( const TQString& filename );
|
|
|
|
void preprocess(bool bPreserveCR, TQTextCodec* pEncoding );
|
|
|
|
void reset();
|
|
|
|
void removeComments();
|
|
|
|
void copyBufFrom( const FileData& src );
|
|
|
|
};
|
|
|
|
FileData m_normalData;
|
|
|
|
FileData m_lmppData;
|
|
|
|
TQTextCodec* m_pEncoding;
|
|
|
|
};
|
|
|
|
|
|
|
|
void calcDiff3LineListTrim( Diff3LineList& d3ll, const LineData* pldA, const LineData* pldB, const LineData* pldC, ManualDiffHelpList* pManualDiffHelpList );
|
|
|
|
void calcWhiteDiff3Lines( Diff3LineList& d3ll, const LineData* pldA, const LineData* pldB, const LineData* pldC );
|
|
|
|
|
|
|
|
void calcDiff3LineVector( Diff3LineList& d3ll, Diff3LineVector& d3lv );
|
|
|
|
|
|
|
|
void debugLineCheck( Diff3LineList& d3ll, int size, int idx );
|
|
|
|
|
|
|
|
class TQStatusBar;
|
|
|
|
|
|
|
|
|
|
|
|
class Selection
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Selection(){ reset(); oldLastLine=-1; lastLine=-1; oldFirstLine=-1; }
|
|
|
|
int firstLine;
|
|
|
|
int firstPos;
|
|
|
|
int lastLine;
|
|
|
|
int lastPos;
|
|
|
|
int oldLastLine;
|
|
|
|
int oldFirstLine;
|
|
|
|
bool bSelectionContainsData;
|
|
|
|
bool isEmpty() { return firstLine==-1 || (firstLine==lastLine && firstPos==lastPos) || bSelectionContainsData==false;}
|
|
|
|
void reset(){
|
|
|
|
oldFirstLine=firstLine;
|
|
|
|
oldLastLine =lastLine;
|
|
|
|
firstLine=-1;
|
|
|
|
lastLine=-1;
|
|
|
|
bSelectionContainsData = false;
|
|
|
|
}
|
|
|
|
void start( int l, int p ) { firstLine = l; firstPos = p; }
|
|
|
|
void end( int l, int p ) {
|
|
|
|
if ( oldLastLine == -1 )
|
|
|
|
oldLastLine = lastLine;
|
|
|
|
lastLine = l;
|
|
|
|
lastPos = p;
|
|
|
|
}
|
|
|
|
bool within( int l, int p );
|
|
|
|
|
|
|
|
bool lineWithin( int l );
|
|
|
|
int firstPosInLine(int l);
|
|
|
|
int lastPosInLine(int l);
|
|
|
|
int beginLine(){
|
|
|
|
if (firstLine<0 && lastLine<0) return -1;
|
|
|
|
return max2(0,min2(firstLine,lastLine));
|
|
|
|
}
|
|
|
|
int endLine(){
|
|
|
|
if (firstLine<0 && lastLine<0) return -1;
|
|
|
|
return max2(firstLine,lastLine);
|
|
|
|
}
|
|
|
|
int beginPos() { return firstLine==lastLine ? min2(firstPos,lastPos) :
|
|
|
|
firstLine<lastLine ? (firstLine<0?0:firstPos) : (lastLine<0?0:lastPos); }
|
|
|
|
int endPos() { return firstLine==lastLine ? max2(firstPos,lastPos) :
|
|
|
|
firstLine<lastLine ? lastPos : firstPos; }
|
|
|
|
};
|
|
|
|
|
|
|
|
class OptionDialog;
|
|
|
|
|
|
|
|
TQCString encodeString( const TQString& s );
|
|
|
|
|
|
|
|
|
|
|
|
// Helper class that swaps left and right for some commands.
|
|
|
|
class MyPainter : public TQPainter
|
|
|
|
{
|
|
|
|
int m_factor;
|
|
|
|
int m_xOffset;
|
|
|
|
int m_fontWidth;
|
|
|
|
public:
|
|
|
|
MyPainter(const TQPaintDevice* pd, bool bRTL, int width, int fontWidth)
|
|
|
|
: TQPainter(const_cast<TQPaintDevice*>(TQT_TQPAINTDEVICE_CONST(pd)))
|
|
|
|
{
|
|
|
|
if (bRTL)
|
|
|
|
{
|
|
|
|
m_fontWidth = fontWidth;
|
|
|
|
m_factor = -1;
|
|
|
|
m_xOffset = width-1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_fontWidth = 0;
|
|
|
|
m_factor = 1;
|
|
|
|
m_xOffset = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void fillRect( int x, int y, int w, int h, const TQBrush& b )
|
|
|
|
{
|
|
|
|
if (m_factor==1)
|
|
|
|
TQPainter::fillRect( m_xOffset + x , y, w, h, b );
|
|
|
|
else
|
|
|
|
TQPainter::fillRect( m_xOffset - x - w, y, w, h, b );
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawText( int x, int y, const TQString& s, bool bAdapt=false )
|
|
|
|
{
|
|
|
|
TextDirection td = (m_factor==1 || bAdapt == false) ? LTR : RTL;
|
|
|
|
TQPainter::drawText( m_xOffset-m_fontWidth*s.length() + m_factor*x, y, s, -1, td );
|
|
|
|
}
|
|
|
|
|
|
|
|
void drawLine( int x1, int y1, int x2, int y2 )
|
|
|
|
{
|
|
|
|
TQPainter::drawLine( m_xOffset + m_factor*x1, y1, m_xOffset + m_factor*x2, y2 );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void fineDiff(
|
|
|
|
Diff3LineList& diff3LineList,
|
|
|
|
int selector,
|
|
|
|
const LineData* v1,
|
|
|
|
const LineData* v2,
|
|
|
|
bool& bTextsTotalEqual
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
bool equal( const LineData& l1, const LineData& l2, bool bStrict );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inline bool isWhite( TQChar c )
|
|
|
|
{
|
|
|
|
return c==' ' || c=='\t' || c=='\r';
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns the number of equivalent spaces at position outPos.
|
|
|
|
*/
|
|
|
|
inline int tabber( int outPos, int tabSize )
|
|
|
|
{
|
|
|
|
return tabSize - ( outPos % tabSize );
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns a line number where the linerange [line, line+nofLines] can
|
|
|
|
be displayed best. If it fits into the currently visible range then
|
|
|
|
the returned value is the current firstLine.
|
|
|
|
*/
|
|
|
|
int getBestFirstLine( int line, int nofLines, int firstLine, int visibleLines );
|
|
|
|
|
|
|
|
extern bool g_bIgnoreWhiteSpace;
|
|
|
|
extern bool g_bIgnoreTrivialMatches;
|
|
|
|
extern int g_bAutoSolve;
|
|
|
|
|
|
|
|
// Cursor conversions that consider g_tabSize.
|
|
|
|
int convertToPosInText( const TQString& s, int posOnScreen, int tabSize );
|
|
|
|
int convertToPosOnScreen( const TQString& s, int posInText, int tabSize );
|
|
|
|
|
|
|
|
enum e_CoordType { eFileCoords, eD3LLineCoords, eWrapCoords };
|
|
|
|
|
|
|
|
void calcTokenPos( const TQString&, int posOnScreen, int& pos1, int& pos2, int tabSize );
|
|
|
|
|
|
|
|
TQString calcHistorySortKey( const TQString& keyOrder, TQRegExp& matchedRegExpr, const TQStringList& parenthesesGroupList );
|
|
|
|
bool findParenthesesGroups( const TQString& s, TQStringList& sl );
|
|
|
|
#endif
|
|
|
|
|