You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kdiff3/src/mergeresultwindow.h

458 lines
16 KiB

/***************************************************************************
mergeresultwindow.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 MERGERESULTWINDOW_H
#define MERGERESULTWINDOW_H
#include "diff.h"
#include <tqwidget.h>
#include <tqpixmap.h>
#include <tqtimer.h>
class TQPainter;
class Overview : public TQWidget
{
TQ_OBJECT
public:
Overview( TQWidget* pParent, OptionDialog* pOptions );
void init( Diff3LineList* pDiff3LineList, bool bTripleDiff );
void reset();
void setRange( int firstLine, int pageHeight );
void setPaintingAllowed( bool bAllowPainting );
enum e_OverviewMode { eOMNormal, eOMAvsB, eOMAvsC, eOMBvsC };
void setOverviewMode( e_OverviewMode eOverviewMode );
e_OverviewMode getOverviewMode();
public slots:
void setFirstLine(int firstLine);
void slotRedraw();
signals:
void setLine(int);
private:
const Diff3LineList* m_pDiff3LineList;
OptionDialog* m_pOptions;
bool m_bTripleDiff;
int m_firstLine;
int m_pageHeight;
TQPixmap m_pixmap;
bool m_bPaintingAllowed;
e_OverviewMode m_eOverviewMode;
int m_nofLines;
virtual void paintEvent( TQPaintEvent* e );
virtual void mousePressEvent( TQMouseEvent* e );
virtual void mouseMoveEvent( TQMouseEvent* e );
void drawColumn( TQPainter& p, e_OverviewMode eOverviewMode, int x, int w, int h, int nofLines );
};
enum e_MergeDetails
{
eDefault,
eNoChange,
eBChanged,
eCChanged,
eBCChanged, // conflict
eBCChangedAndEqual, // possible conflict
eBDeleted,
eCDeleted,
eBCDeleted, // possible conflict
eBChanged_CDeleted, // conflict
eCChanged_BDeleted, // conflict
eBAdded,
eCAdded,
eBCAdded, // conflict
eBCAddedAndEqual // possible conflict
};
void mergeOneLine( const Diff3Line& d, e_MergeDetails& mergeDetails, bool& bConflict, bool& bLineRemoved, int& src, bool bTwoInputs );
enum e_MergeSrcSelector
{
A=1,
B=2,
C=3
};
class MergeResultWindow : public TQWidget
{
TQ_OBJECT
public:
MergeResultWindow(
TQWidget* pParent,
OptionDialog* pOptionDialog,
TQStatusBar* pStatusBar
);
void init(
const LineData* pLineDataA, int sizeA,
const LineData* pLineDataB, int sizeB,
const LineData* pLineDataC, int sizeC,
const Diff3LineList* pDiff3LineList,
TotalDiffStatus* pTotalDiffStatus
);
void reset();
bool saveDocument( const TQString& fileName, TQTextCodec* pEncoding );
int getNrOfUnsolvedConflicts(int* pNrOfWhiteSpaceConflicts=0);
void choose(int selector);
void chooseGlobal(int selector, bool bConflictsOnly, bool bWhiteSpaceOnly );
int getNofColumns();
int getNofLines();
int getNofVisibleColumns();
int getNofVisibleLines();
TQString getSelection();
void resetSelection();
void showNrOfConflicts();
bool isDeltaAboveCurrent();
bool isDeltaBelowCurrent();
bool isConflictAboveCurrent();
bool isConflictBelowCurrent();
bool isUnsolvedConflictAtCurrent();
bool isUnsolvedConflictAboveCurrent();
bool isUnsolvedConflictBelowCurrent();
bool findString( const TQString& s, int& d3vLine, int& posInLine, bool bDirDown, bool bCaseSensitive );
void setSelection( int firstLine, int startPos, int lastLine, int endPos );
void setOverviewMode( Overview::e_OverviewMode eOverviewMode );
Overview::e_OverviewMode getOverviewMode();
public slots:
void setFirstLine(int firstLine);
void setFirstColumn(int firstCol);
void slotGoCurrent();
void slotGoTop();
void slotGoBottom();
void slotGoPrevDelta();
void slotGoNextDelta();
void slotGoPrevUnsolvedConflict();
void slotGoNextUnsolvedConflict();
void slotGoPrevConflict();
void slotGoNextConflict();
void slotAutoSolve();
void slotUnsolve();
void slotMergeHistory();
void slotRegExpAutoMerge();
void slotSplitDiff( int firstD3lLineIdx, int lastD3lLineIdx );
void slotJoinDiffs( int firstD3lLineIdx, int lastD3lLineIdx );
void slotSetFastSelectorLine(int);
void setPaintingAllowed(bool);
void updateSourceMask();
signals:
void scroll( int deltaX, int deltaY );
void modifiedChanged(bool bModified);
void setFastSelectorRange( int line1, int nofLines );
void sourceMask( int srcMask, int enabledMask );
void resizeSignal();
void selectionEnd();
void newSelection();
void updateAvailabilities();
void showPopupMenu( const TQPoint& point );
void noRelevantChangesDetected();
private:
void merge(bool bAutoSolve, int defaultSelector, bool bConflictsOnly=false, bool bWhiteSpaceOnly=false );
TQString getString( int lineIdx );
OptionDialog* m_pOptionDialog;
const LineData* m_pldA;
const LineData* m_pldB;
const LineData* m_pldC;
int m_sizeA;
int m_sizeB;
int m_sizeC;
const Diff3LineList* m_pDiff3LineList;
TotalDiffStatus* m_pTotalDiffStatus;
bool m_bPaintingAllowed;
int m_delayedDrawTimer;
Overview::e_OverviewMode m_eOverviewMode;
private:
class MergeEditLine
{
public:
MergeEditLine(Diff3LineList::const_iterator i, int src=0){m_id3l=i; m_src=src; m_bLineRemoved=false; }
void setConflict() { m_src=0; m_bLineRemoved=false; m_str=TQString(); }
bool isConflict() { return m_src==0 && !m_bLineRemoved && m_str.isNull(); }
void setRemoved(int src=0) { m_src=src; m_bLineRemoved=true; m_str=TQString(); }
bool isRemoved() { return m_bLineRemoved; }
bool isEditableText() { return !isConflict() && !isRemoved(); }
void setString( const TQString& s ){ m_str=s; m_bLineRemoved=false; m_src=0; }
TQString getString( const MergeResultWindow* );
bool isModified() { return ! m_str.isNull() || (m_bLineRemoved && m_src==0); }
void setSource( int src, bool bLineRemoved ) { m_src=src; m_bLineRemoved =bLineRemoved; }
int src() { return m_src; }
Diff3LineList::const_iterator id3l(){return m_id3l;}
// getString() is implemented as MergeResultWindow::getString()
private:
Diff3LineList::const_iterator m_id3l;
int m_src; // 1, 2 or 3 for A, B or C respectively, or 0 when line is from neither source.
TQString m_str; // String when modified by user or null-string when orig data is used.
bool m_bLineRemoved;
};
class MergeEditLineList : private std::list<MergeEditLine>
{ // I want to know the size immediately!
private:
typedef std::list<MergeEditLine> BASE;
int m_size;
int* m_pTotalSize;
public:
typedef std::list<MergeEditLine>::iterator iterator;
typedef std::list<MergeEditLine>::reverse_iterator reverse_iterator;
typedef std::list<MergeEditLine>::const_iterator const_iterator;
MergeEditLineList(){m_size=0; m_pTotalSize=0; }
void clear() { ds(-m_size); BASE::clear(); }
void push_back( const MergeEditLine& m) { ds(+1); BASE::push_back(m); }
void push_front( const MergeEditLine& m) { ds(+1); BASE::push_front(m); }
iterator erase( iterator i ) { ds(-1); return BASE::erase(i); }
iterator insert( iterator i, const MergeEditLine& m ) { ds(+1); return BASE::insert(i,m); }
int size(){ if (!m_pTotalSize) m_size = BASE::size(); return m_size; }
iterator begin(){return BASE::begin();}
iterator end(){return BASE::end();}
reverse_iterator rbegin(){return BASE::rbegin();}
reverse_iterator rend(){return BASE::rend();}
MergeEditLine& front(){return BASE::front();}
MergeEditLine& back(){return BASE::back();}
bool empty() { return m_size==0; }
void splice(iterator destPos, MergeEditLineList& srcList, iterator srcFirst, iterator srcLast)
{
int* pTotalSize = getTotalSizePtr() ? getTotalSizePtr() : srcList.getTotalSizePtr();
srcList.setTotalSizePtr(0); // Force size-recalc after splice, because splice doesn't handle size-tracking
setTotalSizePtr(0);
BASE::splice( destPos, srcList, srcFirst, srcLast );
srcList.setTotalSizePtr( pTotalSize );
setTotalSizePtr( pTotalSize );
}
void setTotalSizePtr(int* pTotalSize)
{
if ( pTotalSize==0 && m_pTotalSize!=0 ) { *m_pTotalSize -= size(); }
else if ( pTotalSize!=0 && m_pTotalSize==0 ) { *pTotalSize += size(); }
m_pTotalSize = pTotalSize;
}
int* getTotalSizePtr()
{
return m_pTotalSize;
}
private:
void ds(int deltaSize)
{
m_size+=deltaSize;
if (m_pTotalSize!=0) *m_pTotalSize+=deltaSize;
}
};
friend class MergeEditLine;
struct MergeLine
{
MergeLine()
{
srcSelect=0; mergeDetails=eDefault; d3lLineIdx = -1; srcRangeLength=0;
bConflict=false; bDelta=false; bWhiteSpaceConflict=false;
}
Diff3LineList::const_iterator id3l;
int d3lLineIdx; // Needed to show the correct window pos.
int srcRangeLength; // how many src-lines have this properties
e_MergeDetails mergeDetails;
bool bConflict;
bool bWhiteSpaceConflict;
bool bDelta;
int srcSelect;
MergeEditLineList mergeEditLineList;
void split( MergeLine& ml2, int d3lLineIdx2 ) // The caller must insert the ml2 after this ml in the m_mergeLineList
{
if ( d3lLineIdx2<d3lLineIdx || d3lLineIdx2 >= d3lLineIdx + srcRangeLength )
return; //Error
ml2.mergeDetails = mergeDetails;
ml2.bConflict = bConflict;
ml2.bWhiteSpaceConflict = bWhiteSpaceConflict;
ml2.bDelta = bDelta;
ml2.srcSelect = srcSelect;
ml2.d3lLineIdx = d3lLineIdx2;
ml2.srcRangeLength = srcRangeLength - (d3lLineIdx2-d3lLineIdx);
srcRangeLength = d3lLineIdx2-d3lLineIdx; // current MergeLine controls fewer lines
ml2.id3l = id3l;
for(int i=0; i<srcRangeLength; ++i)
++ml2.id3l;
ml2.mergeEditLineList.clear();
// Search for best place to splice
for(MergeEditLineList::iterator i=mergeEditLineList.begin(); i!=mergeEditLineList.end();++i)
{
if (i->id3l()==ml2.id3l)
{
ml2.mergeEditLineList.splice( ml2.mergeEditLineList.begin(), mergeEditLineList, i, mergeEditLineList.end() );
return;
}
}
ml2.mergeEditLineList.setTotalSizePtr( mergeEditLineList.getTotalSizePtr() );
ml2.mergeEditLineList.push_back(MergeEditLine(ml2.id3l));
}
void join( MergeLine& ml2 ) // The caller must remove the ml2 from the m_mergeLineList after this call
{
srcRangeLength += ml2.srcRangeLength;
ml2.mergeEditLineList.clear();
mergeEditLineList.clear();
mergeEditLineList.push_back(MergeEditLine(id3l)); // Create a simple conflict
if ( ml2.bConflict ) bConflict = true;
if ( !ml2.bWhiteSpaceConflict ) bWhiteSpaceConflict = false;
if ( ml2.bDelta ) bDelta = true;
}
};
private:
static bool sameKindCheck( const MergeLine& ml1, const MergeLine& ml2 );
struct HistoryMapEntry
{
MergeEditLineList mellA;
MergeEditLineList mellB;
MergeEditLineList mellC;
MergeEditLineList& choice( bool bThreeInputs );
bool staysInPlace( bool bThreeInputs, Diff3LineList::const_iterator& iHistoryEnd );
};
typedef std::map<TQString,HistoryMapEntry> HistoryMap;
void collectHistoryInformation( int src, Diff3LineList::const_iterator iHistoryBegin, Diff3LineList::const_iterator iHistoryEnd, HistoryMap& historyMap, std::list< HistoryMap::iterator >& hitList );
typedef std::list<MergeLine> MergeLineList;
MergeLineList m_mergeLineList;
MergeLineList::iterator m_currentMergeLineIt;
bool isItAtEnd( bool bIncrement, MergeLineList::iterator i )
{
if ( bIncrement ) return i!=m_mergeLineList.end();
else return i!=m_mergeLineList.begin();
}
int m_currentPos;
bool checkOverviewIgnore(MergeLineList::iterator &i);
enum e_Direction { eUp, eDown };
enum e_EndPoint { eDelta, eConflict, eUnsolvedConflict, eLine, eEnd };
void go( e_Direction eDir, e_EndPoint eEndPoint );
void calcIteratorFromLineNr(
int line,
MergeLineList::iterator& mlIt,
MergeEditLineList::iterator& melIt
);
MergeLineList::iterator splitAtDiff3LineIdx( int d3lLineIdx );
virtual void paintEvent( TQPaintEvent* e );
void myUpdate(int afterMilliSecs);
virtual void timerEvent(TQTimerEvent*);
void writeLine(
MyPainter& p, int line, const TQString& str,
int srcSelect, e_MergeDetails mergeDetails, int rangeMark, bool bUserModified, bool bLineRemoved, bool bWhiteSpaceConflict
);
void setFastSelector(MergeLineList::iterator i);
void convertToLinePos( int x, int y, int& line, int& pos );
virtual void mousePressEvent ( TQMouseEvent* e );
virtual void mouseDoubleClickEvent ( TQMouseEvent* e );
virtual void mouseReleaseEvent ( TQMouseEvent * );
virtual void mouseMoveEvent ( TQMouseEvent * );
virtual void resizeEvent( TQResizeEvent* e );
virtual void keyPressEvent( TQKeyEvent* e );
virtual void wheelEvent( TQWheelEvent* e );
virtual void focusInEvent( TQFocusEvent* e );
virtual bool focusNextPrevChild(bool){return false;}
TQPixmap m_pixmap;
int m_firstLine;
int m_firstColumn;
int m_nofColumns;
int m_nofLines;
int m_totalSize; //Same as m_nofLines, but calculated differently
bool m_bMyUpdate;
bool m_bInsertMode;
bool m_bModified;
void setModified(bool bModified=true);
int m_scrollDeltaX;
int m_scrollDeltaY;
int m_cursorXPos;
int m_cursorYPos;
int m_cursorOldXPos;
bool m_bCursorOn; // blinking on and off each second
TQTimer m_cursorTimer;
bool m_bCursorUpdate;
TQStatusBar* m_pStatusBar;
Selection m_selection;
bool deleteSelection2( TQString& str, int& x, int& y,
MergeLineList::iterator& mlIt, MergeEditLineList::iterator& melIt );
bool doRelevantChangesExist();
public slots:
void deleteSelection();
void pasteClipboard(bool bFromSelection);
private slots:
void slotCursorUpdate();
};
class TQLineEdit;
class TQTextCodec;
class TQComboBox;
class TQLabel;
class WindowTitleWidget : public TQWidget
{
TQ_OBJECT
private:
TQLabel* m_pLabel;
TQLineEdit* m_pFileNameLineEdit;
//TQPushButton* m_pBrowseButton;
TQLabel* m_pModifiedLabel;
TQLabel* m_pEncodingLabel;
TQComboBox* m_pEncodingSelector;
OptionDialog* m_pOptionDialog;
std::map<int, TQTextCodec*> m_codecMap;
public:
WindowTitleWidget(OptionDialog* pOptionDialog, TQWidget* pParent );
TQTextCodec* getEncoding();
void setFileName(const TQString& fileName );
TQString getFileName();
void setEncodings( TQTextCodec* pCodecForA, TQTextCodec* pCodecForB, TQTextCodec* pCodecForC );
void setEncoding( TQTextCodec* pCodec );
bool eventFilter( TQObject* o, TQEvent* e );
public slots:
void slotSetModified( bool bModified );
//private slots:
// void slotBrowseButtonClicked();
};
#endif