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