Sfoglia il codice sorgente

整理代码进行开源。删除了商业对比代码和注册代码,除此以外,其余功能全部保留。

爬山虎 3 anni fa
parent
commit
3f0c702276
100 ha cambiato i file con 2469 aggiunte e 0 eliminazioni
  1. 1030 0
      CmpareMode.cpp
  2. 92 0
      CmpareMode.h
  3. 399 0
      Encode.cpp
  4. 26 0
      Encode.h
  5. 130 0
      MediatorDisplay.cpp
  6. 53 0
      MediatorDisplay.h
  7. 58 0
      MediatorFileTree.cpp
  8. 32 0
      MediatorFileTree.h
  9. 138 0
      QTreeWidgetSortItem.cpp
  10. 23 0
      QTreeWidgetSortItem.h
  11. 158 0
      RcTreeWidget.cpp
  12. 46 0
      RcTreeWidget.h
  13. 18 0
      RealCompare.pri
  14. 84 0
      RealCompare.pro
  15. 156 0
      RealCompare.qrc
  16. BIN
      RealCompare.rc
  17. BIN
      Resources/1.png
  18. BIN
      Resources/2.png
  19. BIN
      Resources/3.png
  20. BIN
      Resources/4.png
  21. BIN
      Resources/edit/global/book32.ico
  22. BIN
      Resources/edit/global/book64.ico
  23. BIN
      Resources/edit/global/close.png
  24. BIN
      Resources/edit/global/closehover.png
  25. 0 0
      Resources/edit/global/export-2022-06-30 061114.svg
  26. BIN
      Resources/edit/global/main128.ico
  27. BIN
      Resources/edit/global/main32.ico
  28. BIN
      Resources/edit/global/main64.ico
  29. BIN
      Resources/edit/global/ndd.ico
  30. BIN
      Resources/edit/global/ndd.png
  31. 2 0
      Resources/edit/global/ndd.svg
  32. BIN
      Resources/edit/global/ndd1.ico
  33. BIN
      Resources/edit/global/ndd2.ico
  34. BIN
      Resources/edit/global/ndd4.ico
  35. BIN
      Resources/edit/global/ndd_old.ico
  36. BIN
      Resources/edit/global/ndd_old.png
  37. BIN
      Resources/edit/global/needsave.png
  38. BIN
      Resources/edit/global/noneedsave.png
  39. BIN
      Resources/edit/global/notebook.png
  40. BIN
      Resources/edit/global/notebook128.ico
  41. 20 0
      Resources/edit/global/notepad.svg
  42. 2 0
      Resources/edit/global/txt.svg
  43. 2 0
      Resources/edit/global/txt1.svg
  44. BIN
      Resources/edit/global/wizard_GiletJaune.jpg
  45. BIN
      Resources/edit/global/wizard_GiletJaune1.jpg
  46. BIN
      Resources/edit/styleblack/308上一页、后退、返回.png
  47. BIN
      Resources/edit/styleblack/closeall.png
  48. BIN
      Resources/edit/styleblack/closefile.png
  49. BIN
      Resources/edit/styleblack/closefile2.png
  50. BIN
      Resources/edit/styleblack/copy.png
  51. BIN
      Resources/edit/styleblack/crlf.png
  52. BIN
      Resources/edit/styleblack/cut.png
  53. BIN
      Resources/edit/styleblack/dircompare.png
  54. BIN
      Resources/edit/styleblack/filecompare.png
  55. BIN
      Resources/edit/styleblack/find.png
  56. BIN
      Resources/edit/styleblack/find2.png
  57. BIN
      Resources/edit/styleblack/jhym_goto (1).png
  58. BIN
      Resources/edit/styleblack/needsaveallbar.png
  59. BIN
      Resources/edit/styleblack/needsavebar.png
  60. BIN
      Resources/edit/styleblack/newfile.png
  61. BIN
      Resources/edit/styleblack/noneedsaveallbar.png
  62. BIN
      Resources/edit/styleblack/noneedsavebar.png
  63. BIN
      Resources/edit/styleblack/openfile.png
  64. BIN
      Resources/edit/styleblack/openfile3.png
  65. BIN
      Resources/edit/styleblack/paste.png
  66. BIN
      Resources/edit/styleblack/redo.png
  67. BIN
      Resources/edit/styleblack/redo2.png
  68. BIN
      Resources/edit/styleblack/rename.png
  69. BIN
      Resources/edit/styleblack/rename1.png
  70. BIN
      Resources/edit/styleblack/replace.png
  71. BIN
      Resources/edit/styleblack/replace2.png
  72. BIN
      Resources/edit/styleblack/replace3.png
  73. BIN
      Resources/edit/styleblack/replace4.png
  74. BIN
      Resources/edit/styleblack/save (13).png
  75. BIN
      Resources/edit/styleblack/save (8).png
  76. BIN
      Resources/edit/styleblack/save-all.png
  77. BIN
      Resources/edit/styleblack/save_all.png
  78. BIN
      Resources/edit/styleblack/transcode.png
  79. BIN
      Resources/edit/styleblack/undo.png
  80. BIN
      Resources/edit/styleblack/white.png
  81. BIN
      Resources/edit/styleblack/white2.png
  82. BIN
      Resources/edit/styleblack/zoomin.png
  83. BIN
      Resources/edit/styleblack/zoomout.png
  84. BIN
      Resources/edit/styleblack/下一页 (2).png
  85. BIN
      Resources/edit/styleblack/保存 (7).png
  86. BIN
      Resources/edit/styleblack/保存 (8).png
  87. BIN
      Resources/edit/styleblack/关闭 (4).png
  88. BIN
      Resources/edit/styleblack/关闭 (6).png
  89. BIN
      Resources/edit/styleblack/关闭 (8).png
  90. BIN
      Resources/edit/styleblack/关闭 (9).png
  91. BIN
      Resources/edit/styleblack/关闭所有 (4).png
  92. BIN
      Resources/edit/styleblack/关闭所有_x (1).png
  93. BIN
      Resources/edit/styleblack/右箭头 (1).png
  94. BIN
      Resources/edit/styleblack/对比 (1).png
  95. BIN
      Resources/edit/styleblack/对比度 (1).png
  96. BIN
      Resources/edit/styleblack/对比度 (2).png
  97. BIN
      Resources/edit/styleblack/左箭头 (1).png
  98. BIN
      Resources/edit/styleblack/新建 (5).png
  99. BIN
      Resources/edit/styleblack/新建文件 (1).png
  100. BIN
      Resources/edit/styleblue/Clipboard Paste (2).png

+ 1030 - 0
CmpareMode.cpp

@@ -0,0 +1,1030 @@
+#include "CmpareMode.h"
+#include "Encode.h"
+#include "rcglobal.h"
+
+#include <QFile>
+#include <QFileDevice> 
+#include <QVector>
+#include <QCryptographicHash>
+#include <functional>
+#include <QDataStream>
+#include <QtConcurrent>
+
+
+CmpareMode::CmpareMode()
+{
+}
+
+
+CmpareMode::~CmpareMode()
+{
+	
+}
+
+//识别文字编码,并将文字按照原始编码格式,转换为QString。如果失败,默认按照utf8的格式进行转换;
+bool CmpareMode::recognizeTextCode(QByteArray & text, LineFileInfo &lineInfo, QString &outUnicodeText)
+{
+	int lineNums = lineInfo.lineNums;
+
+	int length = text.count();
+
+	int result = false;
+
+	//第一行时,检测一下文件编码,返回值也是文件的编码
+	if (0 == lineNums)
+	{
+		int skip = 0;
+		lineInfo.code = Encode::DetectEncode((uchar*) text.data(), length, skip);
+		//根据编码跳过第一行前面的几个字符编码标识字段
+		if (skip > 0)
+		{
+			text = text.mid(skip);
+		}
+
+		return Encode::tranStrToUNICODE((CODE_ID)lineInfo.code, text.data(), text.count(), outUnicodeText);
+
+	}
+	else
+	{
+		/*对于头部没有标识的行,需要每行进行详细检查,比较耗时
+		*对于第一行已经是GBK的编码,标识出所有的确是GBK的行号
+		*严格来说,如果以后要做国际版,不应该只考虑GBK,而是要考虑本地ASNI编码。
+		*对中国而言,本地ASNI编码是GBK,对其它国家,比如日本/韩国而言,这些ASNI是它们本国
+		*对应的本地编码。
+		*/
+//#if 0
+//		//全部都在ascii范围以内,就作为ascii码。注意ASCII处理时其它地方时按照UTF8进行编码的
+//		if (Encode::CheckTextIsAllAscii((uchar*)text.data(), length))
+//		{
+//			lineInfo.code = CODE_ID::ASCII;
+//			return Encode::tranStrToUNICODE((CODE_ID)lineInfo.code, text.data(), length, outUnicodeText);
+//		}
+//		else
+//		{
+//#endif
+			CODE_ID actualCode = Encode::CheckUnicodeWithoutBOM((uchar*)text.data(), length, outUnicodeText);
+			if (CODE_ID::UTF8_NOBOM == actualCode)
+			{
+				lineInfo.code = CODE_ID::UTF8_NOBOM;
+				result = true;
+			}
+			else if (CODE_ID::GBK == actualCode)
+			{
+				//如果发现存在GBK,则要以GBK作为字符编码。这里识别gbk是因为显示的时候,需要转化gbk进行显示
+				lineInfo.code = CODE_ID::GBK;
+				result = true;
+			}
+			else if (CODE_ID::ANSI == actualCode)
+			{
+				lineInfo.code = CODE_ID::UNKOWN; //这里就是乱码了。即不是utf8也不是GBK,也不能说乱码,目前其它国家未处理的码
+				result = false;
+			}
+//#if 0
+//		}
+//#endif
+	}
+
+	return result;
+}
+
+
+CODE_ID CmpareMode::getTextFileEncodeType(uchar* fileFpr, int fileLength, QString filePath)
+{
+
+	if (fileLength >= 2 && fileFpr[0] == 0xFF && fileFpr[1] == 0xFE)
+	{
+		return CODE_ID::UNICODE_LE; //skip 2
+	}
+	else if (fileLength >= 2 && fileFpr[0] == 0xFE && fileFpr[1] == 0xFF)
+	{
+		return CODE_ID::UNICODE_BE; //skip 2
+	}
+	else if (fileLength >= 3 && fileFpr[0] == 0xEF && fileFpr[1] == 0xBB && fileFpr[2] == 0xBF)
+	{
+		return CODE_ID::UTF8_BOM; //skip 3 with BOM
+	}
+
+	//走到这里说明没有文件头BOM,进行全盘文件扫描
+	if (!filePath.isEmpty())
+	{
+		return scanFileRealCode(filePath);
+	}
+	
+	return CODE_ID::UNKOWN;
+}
+
+//20210802:发现如果是CODE_ID::UNICODE_LE,\r\n变成了\r\0\n\0,读取readLine遇到\n就结束了,而且toUnicode也会变成乱码失败
+//所以UNICODE_LE需要单独处理。该函数只处理Unicode_LE编码文件,事先一定要检查文件编码
+CODE_ID CmpareMode::readLineFromFileWithUnicodeLe(uchar* m_fileFpr, const int fileLength, QList<LineFileInfo>& lineInfoVec, QList<LineFileInfo>& blankLineInfoVec,int mode, int &maxLineSize)
+{
+	QCryptographicHash md4(QCryptographicHash::Md4);
+
+	int lineNums = 0;
+	CODE_ID code = CODE_ID::UNICODE_LE;
+
+	int lineStartPos = 2; //uicode_le前面有2个特殊标识,故跳过2
+
+	//获取一行在文件中
+	auto getOneLineFromFile = [m_fileFpr](int& startPos, const int fileLength, QByteArray& ret)->bool{
+
+		if (startPos < fileLength)
+		{
+			ret.clear();
+
+			int lineLens = 0;
+
+			bool isFindLine = false;
+
+			for (int i = startPos; i < fileLength; ++i,++lineLens)
+			{
+				//遇到换行符号
+				if (m_fileFpr[i] == 0x0A)
+				{
+					//lineLens需要加2,因为当前这个没有加,而且后面还有一个\0,这是le格式规定的
+					ret.append((char*)(m_fileFpr + startPos), lineLens + 2);
+					startPos += lineLens + 2;
+					isFindLine = true;
+					break;
+				}
+			}
+
+			//没有找到一行
+			if (!isFindLine)
+			{
+				//最后一行,可能没有带\r\0直接返回
+				ret.append((char*)(m_fileFpr + startPos), fileLength - startPos);
+
+				startPos = fileLength;
+			}
+
+			return true;
+			
+		}
+
+		return false;
+	};
+
+	QByteArray line;
+
+	auto work = [mode, &md4](LineFileInfo& lineInfo, const int n) {
+		if (mode == 0)
+		{
+			md4.addData(lineInfo.unicodeStr.trimmed().toUtf8());
+		}
+		else if (mode == 1)
+		{
+			md4.addData(lineInfo.unicodeStr.left(lineInfo.unicodeStr.length() - n).toUtf8());
+		}
+		else if (mode == 2)
+		{
+			QString temp = lineInfo.unicodeStr;
+			md4.addData(temp.replace(QRegExp("\\s"), QString("")).toUtf8());
+		}
+	};
+
+	while (getOneLineFromFile(lineStartPos, fileLength,line)) {
+
+		LineFileInfo lineInfo;
+
+		lineInfo.lineNums = lineNums;
+
+		/* 这种方式读取文件会包含后面的行尾 */
+		int length = line.length();
+
+		if (maxLineSize < length)
+		{
+			maxLineSize = length;
+		}
+
+		//如果是头部有标识的格式,则后续不用详细检查每行编码,直接按照头部标识走
+		Encode::tranStrToUNICODE(code, line.data(), line.count(), lineInfo.unicodeStr);
+		lineInfo.code = code;
+	
+		if (lineInfo.unicodeStr.endsWith("\r\r\n"))
+		{
+			//这里是一种错误,但确实可能出现
+			if (length > 3)
+			{
+				/*if (mode == 0)
+				{
+					md4.addData(lineInfo.unicodeStr.trimmed().toUtf8());
+				}
+				else if (mode == 1)
+				{
+					md4.addData(lineInfo.unicodeStr.left(lineInfo.unicodeStr.length() - 3).toUtf8());
+				}*/
+				work(lineInfo, 3);
+				}
+			else
+			{
+				//空白行
+				lineInfo.isLcsExist = false;
+				lineInfo.isEmptyLine = true;
+			}
+			lineInfo.lineEndFormat = RC_LINE_FORM::DOS_LINE;
+		}
+		else if (lineInfo.unicodeStr.endsWith("\r\n"))
+		{
+			if (length > 2)
+			{
+				/*if (mode == 0)
+				{
+					md4.addData(lineInfo.unicodeStr.trimmed().toUtf8());
+				}
+				else if(mode == 1)
+				{
+					md4.addData(lineInfo.unicodeStr.left(lineInfo.unicodeStr.length() - 2).toUtf8());
+				}*/
+				work(lineInfo, 2);
+				}
+			else
+			{
+				//空白行
+				lineInfo.isLcsExist = false;
+				lineInfo.isEmptyLine = true;
+			}
+			lineInfo.lineEndFormat = RC_LINE_FORM::DOS_LINE;
+
+		}
+		else if (lineInfo.unicodeStr.endsWith("\n"))
+		{
+			if (length > 1)
+			{
+				/*if (mode == 0)
+				{
+					md4.addData(lineInfo.unicodeStr.trimmed().toUtf8());
+				}
+				else if (mode == 1)
+				{
+					md4.addData(lineInfo.unicodeStr.left(lineInfo.unicodeStr.length() - 1).toUtf8());
+				}*/
+				work(lineInfo, 1);
+				}
+			else
+			{
+				lineInfo.isLcsExist = false;
+
+				lineInfo.isEmptyLine = true;
+			}
+			lineInfo.lineEndFormat = RC_LINE_FORM::UNIX_LINE;
+
+		}
+		else if (lineInfo.unicodeStr.endsWith("\r"))
+		{
+			if (length > 1)
+			{
+			/*	if (mode == 0)
+				{
+					md4.addData(lineInfo.unicodeStr.trimmed().toUtf8());
+				}
+				else if (mode == 1)
+				{
+					md4.addData(lineInfo.unicodeStr.left(lineInfo.unicodeStr.length() - 1).toUtf8());
+				}*/
+				work(lineInfo, 1);
+				}
+			else
+			{
+				lineInfo.isLcsExist = false;
+
+				lineInfo.isEmptyLine = true;
+			}
+			lineInfo.lineEndFormat = RC_LINE_FORM::MAC_LINE;
+		}
+		else
+		{
+			if (length > 0)
+			{
+				/*if (mode == 0)
+				{
+					md4.addData(lineInfo.unicodeStr.trimmed().toUtf8());
+				}
+				else if (mode == 1)
+				{
+					md4.addData(lineInfo.unicodeStr.toUtf8());
+				}*/
+				work(lineInfo, 0);
+				}
+			else
+			{
+				lineInfo.isLcsExist = false;
+
+				lineInfo.isEmptyLine = true;
+
+			}
+			lineInfo.lineEndFormat = RC_LINE_FORM::UNKNOWN_LINE;
+		}
+
+		if (lineInfo.isEmptyLine)
+		{
+			blankLineInfoVec.append(lineInfo);
+		}
+		else
+		{
+			lineInfo.md4 = md4.result();
+			//qDebug() << lineInfo.md4;
+			md4.reset();
+			lineInfoVec.append(lineInfo);
+		}
+		++lineNums;
+	}
+
+	return code;
+}
+
+
+//读取每一行,将空白行和非空白行分开。非空白行取他们的行md4值(不包含尾部的换行符)
+//返回值:文件扫描出来的字符编码
+//在对比行的md5值时,忽略了后面的行尾类型。即只对比字符内容,忽略了行尾。
+//20210802:发现如果是CODE_ID::UNICODE_LE,\r\n变成了\r\0\n\0,读取readLine遇到\n就结束了,而且toUnicode也会变成乱码失败
+//所以UNICODE_LE需要单独处理。注意UNICODE_BE没有这个问题,因为BE是\0\r\0\n,0在前面就没有这个问题
+
+//20210901 发现使用readLine的方式来读取一行不可靠。因为有些文件中一行中间有个\r,这种情况没有识别为多行。readLine是根据\n来识别的。
+//进而导致中间的\r没有识别为多行,但是在编辑器中却多一行,导致对比错误。还是要自己来识别行。不依赖于readLine
+
+//CODE_ID fileCode 事先预判定的编码
+CODE_ID CmpareMode::readLineFromFile(uchar* m_fileFpr, const int fileLength, const CODE_ID fileCode, QList<LineFileInfo>&lineInfoVec, QList<LineFileInfo>&blankLineInfoVec, int mode, int &maxLineSize)
+{
+	QCryptographicHash md4(QCryptographicHash::Md4);
+
+	int lineNums = 0;
+	CODE_ID code = fileCode;
+	bool isExistGbk = false;
+	bool isExistUnKownCode = false;
+	bool isExistUtf8 = false;
+
+
+	int lineStartPos = 0; 
+
+	//跳过前面的BOM头部。LE不在这里处理,在外面
+	if (fileCode == CODE_ID::UNICODE_BE || fileCode == CODE_ID::UNICODE_LE)
+	{
+		lineStartPos = 2;
+	}
+	else if (fileCode == CODE_ID::UTF8_BOM)
+	{
+		lineStartPos = 3;
+	}
+
+	//获取一行在文件中
+	auto getOneLineFromFile = [m_fileFpr](int& startPos, const int fileLength, const CODE_ID fileCode, QByteArray& ret)->bool {
+
+		if (startPos < fileLength)
+		{
+			ret.clear();
+
+			int lineLens = 0;
+			bool isFindLine = false;
+
+			for (int i = startPos; i < fileLength; ++i, ++lineLens)
+			{
+				//遇到符号CR
+				if (m_fileFpr[i] == 0x0D)
+				{
+					//后一个是LF,即以CRLF结尾
+					if ((i + 1 < fileLength) && (m_fileFpr[i+1] == 0x0A))
+					{
+						//lineLens需要加2,因为当前这个没有加,而且后面还有一个\n
+						ret.append((char*)(m_fileFpr + startPos), lineLens + 2);
+						startPos += lineLens + 2;
+						isFindLine = true;
+						break;
+					}
+					else if ((fileCode == UNICODE_BE)&&((i>0) && m_fileFpr[i-1] == '\0'))
+					{
+						//事先发现就是BE格式,以\0\r\0\n为结尾的
+						if ((i + 2 < fileLength) && (m_fileFpr[i + 1] == 0x0) && (m_fileFpr[i + 2] == 0x0A))
+						{
+							//lineLens需要加3,因为当前这个没有加,而且后面还有一个\0\n
+							ret.append((char*)(m_fileFpr + startPos), lineLens + 3);
+							startPos += lineLens + 3;
+							isFindLine = true;
+							break;
+						}
+						else 
+						{
+							//虽然说是BE格式,但是后面没有以\0\n结尾,而是以\r结尾。这种多半就是错误。直接按\0\r结尾
+							//lineLens需要加1,因为当前这个没有加
+							ret.append((char*)(m_fileFpr + startPos), lineLens + 1);
+							startPos += lineLens + 1;
+							isFindLine = true;
+							break;
+						}
+
+					}
+					else
+					{
+						//直接以\r结尾了,后面没有\n或者\0\n。符合MAC格式,windows可能编码只有\r,没有\n的错误情况。
+						//lineLens需要加1,因为当前这个没有加
+						ret.append((char*)(m_fileFpr + startPos), lineLens + 1);
+						startPos += lineLens + 1;
+						isFindLine = true;
+						break;
+					}
+				}
+				else if(m_fileFpr[i] == 0x0A)
+				{
+					//没有先遇到\r,直接遇到\n.20210903发现忘记处理该情况le
+					//lineLens需要加1,因为当前这个没有加
+					ret.append((char*)(m_fileFpr + startPos), lineLens + 1);
+					startPos += lineLens + 1;
+					isFindLine = true;
+					break;
+				}
+			}
+
+			//没有找到一行
+			if (!isFindLine)
+			{
+				//最后一行,可能没有带\r\0直接返回
+				ret.append((char*)(m_fileFpr + startPos), fileLength - startPos);
+
+				startPos = fileLength;
+			}
+
+			return true;
+
+		}
+
+		return false;
+	};
+
+	QByteArray line;
+
+	auto work = [mode,&md4](LineFileInfo& lineInfo, const int n) {
+		if (mode == 0)
+		{
+			md4.addData(lineInfo.unicodeStr.trimmed().toUtf8());
+		}
+		else if (mode == 1)
+		{
+			md4.addData(lineInfo.unicodeStr.left(lineInfo.unicodeStr.length() - n).toUtf8());
+		}
+		else if (mode == 2)
+		{
+			QString temp = lineInfo.unicodeStr;
+			md4.addData(temp.replace(QRegExp("\\s"), QString("")).toUtf8());
+		}
+	};
+
+	while (getOneLineFromFile(lineStartPos, fileLength, code, line)) {
+
+		LineFileInfo lineInfo;
+
+		lineInfo.lineNums = lineNums;
+
+		/* 这种方式读取文件会包含后面的行尾 */
+		int length = line.length();
+
+		if (maxLineSize < length)
+		{
+			maxLineSize = length;
+		}
+		//外面必须把code先检测好了
+
+		//if (fileCode == CODE_ID::UNICODE_BE /*|| fileCode == CODE_ID::UNICODE_LE */ || fileCode == CODE_ID::UTF8_BOM)
+		if(fileCode != CODE_ID::UNKOWN)
+		{
+			//如果是头部有标识的格式,则后续不用详细检查每行编码,直接按照头部标识走
+			Encode::tranStrToUNICODE(code, line.data(), line.count(), lineInfo.unicodeStr);
+			lineInfo.code = fileCode;
+		}
+		else if(fileCode == CODE_ID::UNKOWN)
+		{
+			/*对于头部没有标识的行,需要每行进行详细检查,比较耗时
+			*对于第一行已经是GBK的编码,标识出所有的确是GBK的行号
+			*严格来说,如果以后要做国际版,不应该只考虑GBK,而是要考虑本地ASNI编码。
+			*对中国而言,本地ASNI编码是GBK,对其它国家,比如日本/韩国而言,这些ASNI是它们本国
+			*对应的本地编码。
+			*/
+			recognizeTextCode(line, lineInfo, lineInfo.unicodeStr);
+
+			if (CODE_ID::UTF8_NOBOM == lineInfo.code)
+			{
+				isExistUtf8 = true;
+			}
+			else if (CODE_ID::GBK == lineInfo.code)
+			{
+				//如果发现存在GBK,则要以GBK作为字符编码。这里识别gbk是因为显示的时候,需要转化gbk进行显示
+				isExistGbk = true;
+			}
+			else if (CODE_ID::UNKOWN == lineInfo.code)
+			{
+				isExistUnKownCode = true;
+			}
+
+		}
+
+		if (lineInfo.unicodeStr.endsWith("\r\r\n"))
+		{
+			//这里是一种错误,但确实可能出现
+			if (length > 3)
+			{
+				work(lineInfo,3);
+			}
+			else
+			{
+				//空白行
+				lineInfo.isLcsExist = false;
+				lineInfo.isEmptyLine = true;
+			}
+			lineInfo.lineEndFormat = RC_LINE_FORM::DOS_LINE;
+		}
+		else if (lineInfo.unicodeStr.endsWith("\r\n"))
+		{
+			if (length > 2)
+			{
+			
+				work(lineInfo, 2);
+			}
+			else
+			{
+				//空白行
+				lineInfo.isLcsExist = false;
+				lineInfo.isEmptyLine = true;
+			}
+			lineInfo.lineEndFormat = RC_LINE_FORM::DOS_LINE;
+
+		}
+		else if (lineInfo.unicodeStr.endsWith("\n"))
+		{
+			if (length > 1)
+			{
+	
+				work(lineInfo, 1);
+			}
+			else
+			{
+				lineInfo.isLcsExist = false;
+
+				lineInfo.isEmptyLine = true;
+			}
+			lineInfo.lineEndFormat = RC_LINE_FORM::UNIX_LINE;
+
+		}
+		else if (lineInfo.unicodeStr.endsWith("\r"))
+		{
+			if (length > 1)
+			{
+				work(lineInfo, 1);
+			}
+			else
+			{
+				lineInfo.isLcsExist = false;
+
+				lineInfo.isEmptyLine = true;
+			}
+			lineInfo.lineEndFormat = RC_LINE_FORM::MAC_LINE;
+		}
+		else
+		{
+			if (length > 0)
+			{
+				work(lineInfo, 0);
+			}
+			else
+			{
+				lineInfo.isLcsExist = false;
+
+				lineInfo.isEmptyLine = true;
+
+			}
+			lineInfo.lineEndFormat = RC_LINE_FORM::UNKNOWN_LINE;
+		}
+
+		if (lineInfo.isEmptyLine)
+		{
+			blankLineInfoVec.append(lineInfo);
+		}
+		else
+		{
+			lineInfo.md4 = md4.result();
+			md4.reset();
+			lineInfoVec.append(lineInfo);
+		}
+		++lineNums;
+	}
+
+	//如果外部指定了格式,则直接返回外部格式
+	if (fileCode != CODE_ID::UNKOWN)
+	{
+		return fileCode;
+	}
+
+	return judgeFinalTextCode(code, isExistUnKownCode, isExistGbk, isExistUtf8);
+}
+
+CODE_ID CmpareMode::judgeFinalTextCode(CODE_ID code, bool isExistUnKownCode, bool isExistGbk, bool isExistUtf8)
+{
+	//如果是三种有明确标识的字符编码,则严格按照标识的逻辑去读取。哪怕里面存在错误编码,也只能按照头部标识为准
+	if (CODE_ID::UNICODE_LE == code || CODE_ID::UNICODE_BE == code || CODE_ID::UTF8_BOM == code || code == CODE_ID::GBK)
+	{
+		return code;
+	}
+
+	//剩下的是在文件头没有严格标识编码的文件
+	//存在不能识别的编码,则应该是ASNI,需要用户指定编码
+	if (isExistUnKownCode)
+	{
+		return CODE_ID::UNKOWN;
+	}
+	if (isExistGbk)
+	{
+		//如果没有错误码,而且发现gbk,则是gbk编码
+		return CODE_ID::GBK;
+	}
+	//如果不存在错误和gbk,就是纯粹的ut8_nobom
+	if (isExistUtf8)
+	{
+		return CODE_ID::UTF8_NOBOM;
+	}
+
+	return code;
+}
+
+
+//读取用于纯输出,不做比较。bool &isMaybeHexFile 是否是hex文件,不一定准确,做一个推测
+// int& charsNums 输出字符个数
+CODE_ID CmpareMode::readLineFromFile(uchar* m_fileFpr, const int fileLength, const CODE_ID fileCode, QList<LineFileInfo>&lineInfoVec, int& maxLineSize, int& charsNums, bool &isMaybeHexFile)
+{
+	int lineNums = 0;
+	CODE_ID code = fileCode;
+	bool isExistGbk = false;
+	bool isExistUnKownCode = false;
+	bool isExistUtf8 = false;
+	int lineStartPos = 0;
+	int errorCodeLines = 0;
+	charsNums = 0;
+
+	if (fileCode == CODE_ID::UNICODE_BE || fileCode == CODE_ID::UNICODE_LE)
+	{
+		lineStartPos = 2;
+	}
+	else if (fileCode == CODE_ID::UTF8_BOM)
+	{
+		lineStartPos = 3;
+	}
+
+	//获取一行在文件中
+	auto getOneLineFromFile = [m_fileFpr](int& startPos, const int fileLength, const CODE_ID fileCode, QByteArray& ret)->bool {
+
+		if (startPos < fileLength)
+		{
+			ret.clear();
+
+			int lineLens = 0;
+			bool isFindLine = false;
+
+			for (int i = startPos; i < fileLength; ++i, ++lineLens)
+			{
+				//遇到符号CR
+				if (m_fileFpr[i] == 0x0D)
+				{
+					//后一个是LF,即以CRLF结尾
+					if ((i + 1 < fileLength) && (m_fileFpr[i + 1] == 0x0A))
+					{
+						//lineLens需要加2,因为当前这个没有加,而且后面还有一个\n
+						ret.append((char*)(m_fileFpr + startPos), lineLens + 2);
+						startPos += lineLens + 2;
+						isFindLine = true;
+						break;
+					}
+					else if ((fileCode == UNICODE_BE) && ((i > 0) && m_fileFpr[i - 1] == '\0'))
+					{
+						//事先发现就是BE格式,以\0\r\0\n为结尾的
+						if ((i + 2 < fileLength) && (m_fileFpr[i + 1] == 0x0) && (m_fileFpr[i + 2] == 0x0A))
+						{
+							//lineLens需要加3,因为当前这个没有加,而且后面还有一个\0\n
+							ret.append((char*)(m_fileFpr + startPos), lineLens + 3);
+							startPos += lineLens + 3;
+							isFindLine = true;
+							break;
+						}
+						else
+						{
+							//虽然说是BE格式,但是后面没有以\0\n结尾,而是以\r结尾。这种多半就是错误。直接按\0\r结尾
+							//lineLens需要加1,因为当前这个没有加
+							ret.append((char*)(m_fileFpr + startPos), lineLens + 1);
+							startPos += lineLens + 1;
+							isFindLine = true;
+							break;
+						}
+
+					}
+					else
+					{
+						//直接以\r结尾了,后面没有\n或者\0\n。符合MAC格式,windows可能编码只有\r,没有\n的错误情况。
+						//lineLens需要加1,因为当前这个没有加
+						ret.append((char*)(m_fileFpr + startPos), lineLens + 1);
+						startPos += lineLens + 1;
+						isFindLine = true;
+						break;
+					}
+				}
+				else if (m_fileFpr[i] == 0x0A)
+				{
+					//没有先遇到\r,直接遇到\n.20210903发现忘记处理该情况le
+					//lineLens需要加1,因为当前这个没有加
+					ret.append((char*)(m_fileFpr + startPos), lineLens + 1);
+					startPos += lineLens + 1;
+					isFindLine = true;
+					break;
+				}
+			}
+
+			//没有找到一行
+			if (!isFindLine)
+			{
+				//最后一行,可能没有带\r\0直接返回
+				ret.append((char*)(m_fileFpr + startPos), fileLength - startPos);
+
+				startPos = fileLength;
+			}
+
+			return true;
+
+		}
+
+		return false;
+	};
+
+	QByteArray line;
+
+
+	while (getOneLineFromFile(lineStartPos, fileLength, code, line)) {
+
+		LineFileInfo lineInfo;
+
+		lineInfo.lineNums = lineNums;
+
+		/* 这种方式读取文件会包含后面的行尾 */
+		int length = line.length();
+
+		if (maxLineSize < length)
+		{
+			maxLineSize = length;
+		}
+
+		//外面必须把code先检测好了
+
+		//if (fileCode == CODE_ID::UNICODE_BE /*|| fileCode == CODE_ID::UNICODE_LE */ || fileCode == CODE_ID::UTF8_BOM)
+		if(fileCode != CODE_ID::UNKOWN)
+		{
+			//如果是头部有标识的格式,则后续不用详细检查每行编码,直接按照头部标识走
+			Encode::tranStrToUNICODE(code, line.data(), line.count(), lineInfo.unicodeStr);
+			lineInfo.code = fileCode;
+		}
+		else if (fileCode == CODE_ID::UNKOWN)
+		{
+			/*对于头部没有标识的行,需要每行进行详细检查,比较耗时
+			*对于第一行已经是GBK的编码,标识出所有的确是GBK的行号
+			*严格来说,如果以后要做国际版,不应该只考虑GBK,而是要考虑本地ASNI编码。
+			*对中国而言,本地ASNI编码是GBK,对其它国家,比如日本/韩国而言,这些ASNI是它们本国
+			*对应的本地编码。
+			*/
+			recognizeTextCode(line, lineInfo, lineInfo.unicodeStr);
+
+			if (CODE_ID::UTF8_NOBOM == lineInfo.code)
+			{
+				isExistUtf8 = true;
+			}
+			else if (CODE_ID::GBK == lineInfo.code)
+			{
+				//如果发现存在GBK,则要以GBK作为字符编码。这里识别gbk是因为显示的时候,需要转化gbk进行显示
+				isExistGbk = true;
+			}
+			else if (CODE_ID::UNKOWN == lineInfo.code)
+			{
+				isExistUnKownCode = true;
+
+				//增加错误行的计数
+				errorCodeLines++;
+			}
+
+		}
+
+		if (lineInfo.unicodeStr.endsWith("\r\r\n"))
+		{
+			//这里是一种错误,但确实可能出现
+			if (length > 3)
+			{
+
+			}
+			else
+			{
+				//空白行
+				lineInfo.isLcsExist = false;
+				lineInfo.isEmptyLine = true;
+			}
+			lineInfo.lineEndFormat = RC_LINE_FORM::DOS_LINE;
+		}
+		else if (lineInfo.unicodeStr.endsWith("\r\n"))
+		{
+			if (length > 2)
+			{
+				
+			}
+			else
+			{
+				//空白行
+				lineInfo.isLcsExist = false;
+				lineInfo.isEmptyLine = true;
+			}
+			lineInfo.lineEndFormat = RC_LINE_FORM::DOS_LINE;
+
+		}
+		else if (lineInfo.unicodeStr.endsWith("\n"))
+		{
+			if (length > 1)
+			{
+				
+			}
+			else
+			{
+				lineInfo.isLcsExist = false;
+
+				lineInfo.isEmptyLine = true;
+			}
+			lineInfo.lineEndFormat = RC_LINE_FORM::UNIX_LINE;
+
+		}
+		else if (lineInfo.unicodeStr.endsWith("\r"))
+		{
+			if (length > 1)
+			{
+				
+			}
+			else
+			{
+				lineInfo.isLcsExist = false;
+
+				lineInfo.isEmptyLine = true;
+			}
+			lineInfo.lineEndFormat = RC_LINE_FORM::MAC_LINE;
+		}
+		else
+		{
+			if (length > 0)
+			{
+				
+			}
+			else
+			{
+				lineInfo.isLcsExist = false;
+
+				lineInfo.isEmptyLine = true;
+
+			}
+			lineInfo.lineEndFormat = RC_LINE_FORM::UNKNOWN_LINE;
+		}
+
+		lineInfoVec.append(lineInfo);
+		
+		charsNums += lineInfo.unicodeStr.size();
+		++lineNums;
+	}
+
+	//如果超过一半的行都是错误的,则考虑为hex文件。
+	if (lineNums >= 10 && (errorCodeLines * 100 / lineNums > 50))
+	{
+		isMaybeHexFile = true;
+	}
+	else
+	{
+		isMaybeHexFile = false;
+
+		//如果前面三行中含有\0字符,也可能是二进制文件
+		if (lineNums > 3)
+		{
+			for (int i = 0; i < 3; ++i)
+			{
+				if (lineInfoVec.at(i).unicodeStr.contains(QChar('\0')))
+				{
+					isMaybeHexFile = true;
+					break;
+				}
+			}
+		}
+	}
+
+	//如果用户外部强制编码,则直接按改编码返回
+	if (fileCode != CODE_ID::UNKOWN)
+	{
+		return fileCode;
+	}
+
+	return judgeFinalTextCode(code, isExistUnKownCode, isExistGbk, isExistUtf8);
+}
+
+
+//扫描文件的字符编码,不输出文件
+CODE_ID CmpareMode::scanFileRealCode(QString filePath)
+{
+	QFile file(filePath);
+	file.open(QIODevice::ReadOnly);
+	
+	CODE_ID code = CODE_ID::UNKOWN;
+	int lineNums = 0;
+
+	bool isExistGbk = false;
+	bool isExistUnKownCode = false;
+	bool isExistUtf8 = false;
+
+
+	while (!file.atEnd()) {
+
+		LineFileInfo lineInfo;
+
+		QByteArray line = file.readLine();
+
+		lineInfo.lineNums = lineNums;
+
+		/* 这种方式读取文件会包含后面的行尾 */
+		//int length = line.length();
+
+		//第一行时,检测一下文件编码,返回值也是文件的编码
+		if (0 == lineNums)
+		{
+			recognizeTextCode(line, lineInfo, lineInfo.unicodeStr);
+			code = (CODE_ID)lineInfo.code;
+
+			//已经找到文本的标签,相信标签,之前返回
+			if (code == CODE_ID::UNICODE_BE || code == CODE_ID::UNICODE_LE || code == CODE_ID::UTF8_BOM || code == CODE_ID::GBK)
+			{
+				break;
+			}
+
+		}
+		else
+		{
+			/*对于头部没有标识的行,需要每行进行详细检查,比较耗时
+			*对于第一行已经是GBK的编码,标识出所有的确是GBK的行号
+			*严格来说,如果以后要做国际版,不应该只考虑GBK,而是要考虑本地ASNI编码。
+			*对中国而言,本地ASNI编码是GBK,对其它国家,比如日本/韩国而言,这些ASNI是它们本国
+			*对应的本地编码。
+			*/
+			recognizeTextCode(line, lineInfo, lineInfo.unicodeStr);
+
+			if (CODE_ID::UTF8_NOBOM == lineInfo.code)
+			{
+				isExistUtf8 = true;
+			}
+			else if (CODE_ID::GBK == lineInfo.code)
+			{
+				//如果发现存在GBK,则要以GBK作为字符编码。这里识别gbk是因为显示的时候,需要转化gbk进行显示
+				isExistGbk = true;
+			}
+			else if (CODE_ID::UNKOWN == lineInfo.code)
+			{
+				isExistUnKownCode = true;
+				//20220127一旦发现错误编码,或者说不能识别的编码,则直接跳出。
+				//因为肯定是不能识别的编码ASNI
+				break;
+			}
+
+		}
+
+		++lineNums;
+
+		if (lineNums >= 1000)
+		{
+			break;
+		}
+	}
+
+	file.close();
+
+	return judgeFinalTextCode(code, isExistUnKownCode, isExistGbk, isExistUtf8);
+
+}
+
+//读取文件,并输出
+//bytescharsNums:文件字符个数,不是文件大小
+//20220908 自动判断是否是二进制文件。isHexFile 是输出
+CODE_ID CmpareMode::scanFileOutPut(CODE_ID code, QString filePath, QList<LineFileInfo>& outputLineInfoVec, int &maxLineSize, int& charsNums, bool &isHexFile)
+{
+	QFile* file = new QFile(filePath);
+	file->open(QIODevice::ReadOnly);
+	uchar* m_fileFpr = file->map(0, file->size());
+
+	if (code == UNKOWN)
+	{
+		code = getTextFileEncodeType(m_fileFpr, file->size(), filePath);
+	}
+
+	//UNICODE_LE格式需要单独处理
+	if (code == UNICODE_LE)
+	{
+		readLineFromFileWithUnicodeLe(m_fileFpr, file->size(), outputLineInfoVec, outputLineInfoVec, 0, maxLineSize);
+	}
+	else
+	{
+		code = readLineFromFile(m_fileFpr, file->size(), code, outputLineInfoVec, maxLineSize, charsNums, isHexFile);
+	}
+
+	file->unmap(m_fileFpr);
+	file->close();
+	delete file;
+
+	return code;
+}

+ 92 - 0
CmpareMode.h

@@ -0,0 +1,92 @@
+#pragma once
+#include <qobject.h>
+#include<QVector>
+#include<QMap>
+#include <QFuture>
+
+#include <functional>
+#include "rcglobal.h"
+#include "Encode.h"
+
+
+class BlockUserData;
+class QFile;
+
+
+const int LEFT = 0;
+const int RIGHT = 1;
+
+//对比bin二进制文件。
+const int MAX_BIN_SIZE = 1024 * 1024 * 10; //最大10M
+
+typedef void(* CALL_FUNC)(void *, uchar *, int);
+
+typedef struct lineFileInfo_ {
+	qint32 lineNums; //行号码
+	bool isLcsExist;//是否属于lcsline的一部分
+	bool isEmptyLine; //是否是空白行,只包含换行符的行
+	int code; //该行的字符编码
+	int lineEndFormat; //行尾:见RC_LINE_FORM
+	QByteArray md4;
+	QString unicodeStr; //这个是包含行尾的换行符的
+	lineFileInfo_()
+	{
+		isLcsExist = false;
+		isEmptyLine = false;
+		code = UNKOWN;
+		lineEndFormat = UNKNOWN_LINE;
+	}
+}LineFileInfo;
+
+
+
+const int EMPTY_FILE = 0;
+const int SCAN_SUCCESS = 1;
+
+class CmpareMode;
+
+typedef struct ThreadFileCmpParameter_ {
+	QString leftPath;
+	QString rightPath;
+	CmpareMode *resultCmpObj;
+
+	ThreadFileCmpParameter_(QString leftPath_, QString rightPath_)
+	{
+		leftPath = leftPath_;
+		rightPath = rightPath_;
+		resultCmpObj = nullptr;
+	}
+
+}ThreadFileCmpParameter;
+
+class CmpareMode :public QObject
+{
+	Q_OBJECT
+public:
+	CmpareMode();
+	virtual ~CmpareMode();
+
+	static CODE_ID readLineFromFile(uchar * m_fileFpr, const int fileLength, const CODE_ID fileCode, QList<LineFileInfo>& lineInfoVec, QList<LineFileInfo>& blankLineInfoVec, int mode, int& maxLineSize);
+	static CODE_ID judgeFinalTextCode(CODE_ID code, bool isExistUnKownCode, bool isExistGbk, bool isExistUtf8);
+	static CODE_ID readLineFromFile(uchar * m_fileFpr, const int fileLength, const CODE_ID fileCode, QList<LineFileInfo>& lineInfoVec,int& maxLineSize, int& charsNums, bool &isMaybeHexFile);
+
+	static CODE_ID scanFileRealCode(QString filePath);
+	static CODE_ID scanFileOutPut(CODE_ID code, QString filePath, QList<LineFileInfo>& outputLineInfoVec, int & maxLineSize, int & charsNums, bool &isHexFile);
+
+
+	inline QList<LineFileInfo>* getLeftLineInfo();
+	inline QList<LineFileInfo>* getRightLineInfo();
+
+
+	void getLines(RC_DIRECTION direction, QList<LineFileInfo>& lines);
+	void getLinesExternInfo(QList<BlockUserData*>*& leftExternBlockInfo, QList<BlockUserData*>*& rightExternBlockInfo);
+
+private:
+
+	static bool recognizeTextCode(QByteArray & text, LineFileInfo & lineInfo, QString & outUnicodeText);
+	static CODE_ID getTextFileEncodeType(uchar* fileFpr, int fileLength, QString filePath);
+	CODE_ID static readLineFromFileWithUnicodeLe(uchar* m_fileFpr, const int fileLength, QList<LineFileInfo>& lineInfoVec, QList<LineFileInfo>& blankLineInfoVec,int mode, int &maxLineSize);
+
+	
+};
+

+ 399 - 0
Encode.cpp

@@ -0,0 +1,399 @@
+#include "Encode.h"
+#include <QTextCodec>
+#include <QtDebug>
+
+/* 检查字符串编码的类。看了大量文献,结论如下:
+*如果是UTF BOM格式,或者UNICODE格式,其文件头部前几个字节(2-3)有一定的标识。由此标识直接按对应编码处理。
+*如果没有标识,默认就是UTF8(NO BOM) 与 ANSI(现在只考虑GBK)进行对比。
+*此时需要做统计分析。对所有行进行UTF8解析,如果按照UTF8解析错位再按照GBK解析。如果解析出GBK那么大概率认为文件是GBK编码的。
+*/
+
+Encode::Encode()
+{
+
+}
+
+Encode::~Encode()
+{
+
+}
+
+CODE_ID Encode::getCodeByName(QString name)
+{
+	CODE_ID id;
+
+	if (name == "unknown")
+	{
+		id = CODE_ID::UNKOWN;
+	}
+	else if (name == "UTF16-LE")
+	{
+		id = CODE_ID::UNICODE_LE;
+	}
+	else if (name == "UTF16-BE")
+	{
+		id = CODE_ID::UNICODE_BE;
+	}
+	else if (name == "UTF8")
+	{
+		id = CODE_ID::UTF8_NOBOM;
+	}
+	else if (name == "UTF8-BOM")
+	{
+		id = CODE_ID::UTF8_BOM;
+	}
+	else if (name == "GBK")
+	{
+		id = CODE_ID::GBK;
+	}
+	else if (name == "EUC-JP")
+	{
+		id = CODE_ID::EUC_JP;
+	}
+	else if (name == "Shift-JIS")
+	{
+		id = CODE_ID::Shift_JIS;
+	}
+	else if (name == "EUC-KR")
+	{
+		id = CODE_ID::EUC_KR;
+	}
+	else if (name == "KOI8-R")
+	{
+		id = CODE_ID::KOI8_R;
+	}
+	else if (name == "TSCII")
+	{
+		id = CODE_ID::TSCII;
+	}
+	else if (name == "TIS-620")
+	{
+		id = CODE_ID::TIS_620;
+	}
+	else
+	{
+		id = CODE_ID::UNKOWN;
+	}
+
+	return id;
+
+}
+
+QString Encode::getLineEndById(RC_LINE_FORM id)
+{
+	QString ret;
+
+	switch (id)
+	{
+	case PAD_LINE:
+	case UNKNOWN_LINE:
+#ifdef WIN32
+		ret = "Windows(CR LF)";
+#else
+		ret = "Unix(LF)";
+#endif
+		ret = "NULL";
+		break;
+	case UNIX_LINE:
+		ret = "Unix(LF)";
+		break;
+	case DOS_LINE:
+		ret = "Windows(CR LF)";
+		break;
+	case MAC_LINE:
+		ret = "Mac(CR)";
+		break;
+	default:
+		break;
+	}
+	return  ret;
+}
+
+QString Encode::getCodeNameById(CODE_ID id)
+{
+	QString ret;
+
+	switch (id)
+	{
+	case UNKOWN:
+		ret = "unknown";
+		break;
+	case ANSI:
+		ret = "unknown";
+		break;
+	case UNICODE_LE:
+		ret = "UTF16-LE";
+		break;
+	case UNICODE_BE:
+		ret = "UTF16-BE";
+		break;
+	case UTF8_NOBOM:
+		ret = "UTF8";
+		break;
+	case UTF8_BOM:
+		ret = "UTF8-BOM";
+		break;
+	case GBK:
+		ret = "GBK";
+		break;
+	case EUC_JP:
+		ret = "EUC-JP";
+		break;
+	case Shift_JIS:
+		ret = "Shift-JIS";
+		break;
+	case EUC_KR:
+		ret = "EUC-KR";
+		break;
+	case KOI8_R:
+		ret = "KOI8-R";
+		break;
+	case TSCII:
+		ret = "TSCII";
+		break;
+	case TIS_620:
+		ret = "TIS-620";
+		break;
+	default:
+		ret = "unknown";
+		break;
+	}
+
+	return ret;
+}
+
+QByteArray Encode::getEncodeStartFlagByte(CODE_ID code)
+{
+	QByteArray ret;
+
+	switch (code)
+	{
+		case UNICODE_LE:
+		{
+			ret.append((char)0xFF);
+			ret.append((char)0xFE);
+		}
+		break;
+
+		case UNICODE_BE:
+		{
+		ret.append((char)0xFE);
+		ret.append((char)0xFF);
+		}
+		break;
+
+		case UTF8_BOM:
+		{
+			ret.append((char)0xEF);
+			ret.append((char)0xBB);
+			ret.append((char)0xBF);
+		}
+		break;
+
+		default:
+			break;
+	}
+
+	return ret;
+}
+
+CODE_ID Encode::DetectEncode(const uchar* pBuffer, int length, int &skip)
+{
+	if (pBuffer[0] == 0xFF && pBuffer[1] == 0xFE)
+	{
+		skip = 2;
+		return CODE_ID::UNICODE_LE; //skip 2
+	}
+	if (pBuffer[0] == 0xFE && pBuffer[1] == 0xFF)
+	{
+		skip = 2;
+		return CODE_ID::UNICODE_BE; //skip 2
+	}
+	if (pBuffer[0] == 0xEF && pBuffer[1] == 0xBB && pBuffer[2] == 0xBF)
+	{
+		skip = 3;
+		return CODE_ID::UTF8_BOM; //skip 3 with BOM
+	}
+
+	// 不能知道是不是UTF8
+	CODE_ID code = CheckUnicodeWithoutBOM(pBuffer, length);
+
+	skip = 0;
+	return code; //skip 0
+
+}
+
+bool Encode::tranGbkToUNICODE(const char* pText, int length, QString &out)
+{
+	QTextCodec::ConverterState state;
+	
+	QTextCodec *codec = QTextCodec::codecForName("GBK");
+	out = codec->toUnicode((const char *)pText, length, &state);
+	if (state.invalidChars > 0) {
+		return false;
+	}
+	return true;
+}
+
+bool Encode::tranUtf8ToUNICODE(const char* pText, int length, QString &out)
+{
+	QTextCodec::ConverterState state;
+
+	QTextCodec *codec = QTextCodec::codecForName("UTF-8");
+	out = codec->toUnicode((const char *)pText, length, &state);
+	if (state.invalidChars > 0) {
+		return false;
+	}
+	return true;
+}
+
+//与getCodeNameById类似,但是返回的是QT系统支持的编码的字符串名称
+QString Encode::getQtCodecNameById(CODE_ID id)
+{
+	QString ret;
+
+	switch (id)
+	{
+	case UNKOWN:
+	case ANSI:
+		ret = "unknown";
+		break;
+	case UNICODE_LE:
+		ret = "UTF16-LE";
+		break;
+	case UNICODE_BE:
+		ret = "UTF16-BE";
+		break;
+	case UTF8_NOBOM://qt没有这种
+	case UTF8_BOM:
+		ret = "UTF8";
+		break;
+	case GBK:
+		ret = "GBK";
+		break;
+	case EUC_JP:
+		ret = "EUC-JP";
+		break;
+	case Shift_JIS:
+		ret = "Shift-JIS";
+		break;
+	case EUC_KR:
+		ret = "EUC-KR";
+		break;
+	case KOI8_R:
+		ret = "KOI8-R";
+		break;
+	case TSCII:
+		ret = "TSCII";
+		break;
+	case TIS_620:
+		ret = "TIS-620";
+		break;
+	default:
+		ret = "unknown";
+		break;
+	}
+
+	return ret;
+}
+
+//将指定编码的字符串转换到unicode
+bool Encode::tranStrToUNICODE(CODE_ID code, const char* pText, int length, QString &out)
+{
+	if (length < 0)
+	{
+		return false;
+	}
+
+	QTextCodec::ConverterState state;
+	QTextCodec *codec = nullptr;
+
+	QString textCodeName = getQtCodecNameById(code);
+	if (textCodeName.isEmpty() || textCodeName == "unknown")
+	{
+		//对于其它非识别编码,统一转换为utf8。减去让用户选择的麻烦
+		//这里其实是有问题的。先这样简单处理
+		codec = QTextCodec::codecForName("UTF-8");
+	}
+	else
+	{
+		codec = QTextCodec::codecForName(textCodeName.toStdString().c_str());
+	}
+	
+	if (codec == nullptr)
+	{
+		return false;
+	}
+
+	out = codec->toUnicode((const char *)pText, length, &state);
+	if (state.invalidChars > 0) {
+		return false;
+	}
+	return true;
+}
+
+/* 这里其实是穷举字符串的字符编码;ASNI utf8。目前只检测GBK和utf8;其它语种没有穷举
+*GB2312 GBK GB18030 三种差别见https://cloud.tencent.com/developer/article/1343240
+*关于编码的详细说明,见https://blog.csdn.net/libaineu2004/article/details/19245205
+*/
+//这里是有限检查utf8的,如果出现gbk,说明一定不是utf8,因为utf8检查到错误码。
+CODE_ID Encode::CheckUnicodeWithoutBOM(const uchar* pText, int length)
+{
+	QTextCodec::ConverterState state;
+	QTextCodec *codec = QTextCodec::codecForName("UTF-8");
+	const QString text = codec->toUnicode((const char *)pText, length, &state);
+	if (state.invalidChars > 0) {
+		/*不是UTF-8格式的文件,这里优先判断是不是UTF8,再判断是不是GBK;我们先做中文版;如果后续要做
+		*国际版,其实不应该只检查GBK,而是应该检查本地ASCI码,包括ascii码*/
+		QTextCodec::ConverterState state1;
+		QTextCodec *codec1 = QTextCodec::codecForName("GBK");
+		codec1->toUnicode((const char *)pText, length, &state1);
+		if (state1.invalidChars > 0) {
+			return CODE_ID::ANSI;
+		}
+		else
+		{
+			return CODE_ID::GBK;
+		}
+	}
+
+	return CODE_ID::UTF8_NOBOM;
+}
+
+CODE_ID Encode::CheckUnicodeWithoutBOM(const uchar* pText, int length, QString &outUnicodeText)
+{
+	QTextCodec::ConverterState state;
+	QTextCodec *codec = QTextCodec::codecForName("UTF-8");
+	outUnicodeText = codec->toUnicode((const char *)pText, length, &state);
+	if (state.invalidChars > 0) {
+		/*不是UTF-8格式的文件,这里优先判断是不是UTF8,再判断是不是GBK;我们先做中文版;如果后续要做
+		*国际版,其实不应该只检查GBK,而是因为检查本地ASCI码,包括ascii码*/
+		QTextCodec::ConverterState state1;
+		QTextCodec *codec1 = QTextCodec::codecForName("GBK");
+		QString gbkStr = codec1->toUnicode((const char *)pText, length, &state1);
+		if (state1.invalidChars > 0) {
+			//如果也不是gbk,姑且按照utf8直接返回
+			return CODE_ID::ANSI;
+		}
+		else
+		{
+			outUnicodeText = gbkStr;
+			return CODE_ID::GBK;
+		}
+	}
+
+	return CODE_ID::UTF8_NOBOM;
+}
+
+//检查是否全是ascii字符码
+bool Encode::CheckTextIsAllAscii(const uchar* pText, int length)
+{
+	for (int i = 0; i < length; ++i)
+	{
+		if (*(pText + i) < 0 || *(pText + i) > 0x7F)
+		{
+			return false;
+		}
+	}
+	return true;
+}

+ 26 - 0
Encode.h

@@ -0,0 +1,26 @@
+#pragma once
+#include <QtGlobal>
+
+//#define GBK_
+#include "rcglobal.h"
+
+
+class Encode
+{
+public:
+	Encode();
+	~Encode();
+	static CODE_ID getCodeByName(QString name);
+	static QString getLineEndById(RC_LINE_FORM id);
+	static QString getCodeNameById(CODE_ID id);
+	static QByteArray getEncodeStartFlagByte(CODE_ID code);
+	static CODE_ID DetectEncode(const uchar* pBuffer, int length,int &skip);
+	static bool tranGbkToUNICODE(const char* pText, int length, QString &out);
+	static bool tranUtf8ToUNICODE(const char * pText, int length, QString & out);
+	static QString getQtCodecNameById(CODE_ID id);
+	static bool tranStrToUNICODE(CODE_ID code, const char * pText, int length, QString & out);
+	static CODE_ID CheckUnicodeWithoutBOM(const uchar * pText, int length);
+	static CODE_ID CheckUnicodeWithoutBOM(const uchar * pText, int length, QString & outUnicodeText);
+	static bool CheckTextIsAllAscii(const uchar * pText, int length);
+};
+

+ 130 - 0
MediatorDisplay.cpp

@@ -0,0 +1,130 @@
+#include "MediatorDisplay.h"
+
+
+//这里如果直接让左右互相同步,互相影响,可能导致混乱。需要一个中间调停者模式,作为中间人去控制同步消息
+//中介者模式意图:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
+//主要解决:对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。
+//之前不使用该模式时,左右显示同步互相交互,时而发生消息混乱
+
+MediatorDisplay::MediatorDisplay():QObject(nullptr)
+{
+	m_leftLineNum = 0;
+	m_rightLineNum = 0;
+	m_leftScrollValue = 0;
+	m_rightScrollValue = 0;
+
+}
+
+MediatorDisplay::~MediatorDisplay()
+{
+}
+
+void MediatorDisplay::setLeftNum(int value)
+{
+	 m_leftLineNum = value;
+	 if (m_leftLineNum != m_rightLineNum)
+	 {
+		 emit syncCurLineNum(0);
+	 }
+	
+}
+
+void MediatorDisplay::setRightNum(int value)
+{
+	m_rightLineNum = value;
+	if (m_leftLineNum != m_rightLineNum)
+	{
+		emit syncCurLineNum(1);
+	}
+}
+
+int MediatorDisplay::getLeftNum()
+{
+	return m_leftLineNum;
+}
+
+int MediatorDisplay::getRightNum()
+{
+	return m_rightLineNum;
+}
+
+void MediatorDisplay::setLeftScrollValue(int value)
+{
+	if (m_leftScrollValue != value)
+	{
+		m_leftScrollValue = value;
+	}
+	
+
+	//如果左右不相等,则推动对方去同步
+	if (m_leftScrollValue != m_rightScrollValue)
+	{
+		emit syncCurScrollValue(0);
+	}
+
+}
+
+void MediatorDisplay::setRightScrollValue(int value)
+{
+	if (m_rightScrollValue != value)
+	{
+		m_rightScrollValue = value;
+	}
+	
+
+	if (m_leftScrollValue != m_rightScrollValue)
+	{
+		emit syncCurScrollValue(1);
+	}
+}
+
+int MediatorDisplay::getLeftScrollValue()
+{
+	return m_leftScrollValue;
+}
+
+int MediatorDisplay::getRightScrollValue()
+{
+	return m_rightScrollValue;
+}
+
+
+void MediatorDisplay::setLeftScrollXValue(int value)
+{
+	if (m_leftScrollXValue != value)
+	{
+		m_leftScrollXValue = value;
+	}
+
+
+	//如果左右不相等,则推动对方去同步
+	if (m_leftScrollXValue != m_rightScrollXValue)
+	{
+		emit syncCurScrollXValue(0);
+	}
+
+}
+
+void MediatorDisplay::setRightScrollXValue(int value)
+{
+	if (m_rightScrollXValue != value)
+	{
+		m_rightScrollXValue = value;
+	}
+
+
+	if (m_leftScrollXValue != m_rightScrollXValue)
+	{
+		emit syncCurScrollXValue(1);
+	}
+}
+
+int MediatorDisplay::getLeftScrollXValue()
+{
+	return m_leftScrollXValue;
+}
+
+int MediatorDisplay::getRightScrollXValue()
+{
+	return m_rightScrollXValue;
+}

+ 53 - 0
MediatorDisplay.h

@@ -0,0 +1,53 @@
+#pragma once
+#include <QObject>
+
+class MediatorDisplay:public QObject
+{
+	Q_OBJECT
+public:
+	MediatorDisplay();
+	virtual ~MediatorDisplay();
+
+	void setLeftNum(int value);
+	void setRightNum(int value);
+
+	int getLeftNum();
+	int getRightNum();
+
+	void setLeftScrollValue(int value);
+	void setRightScrollValue(int value);
+
+	int getLeftScrollValue();
+	int getRightScrollValue();
+
+	void setLeftScrollXValue(int value);
+
+	void setRightScrollXValue(int value);
+
+	int getLeftScrollXValue();
+
+	int getRightScrollXValue();
+
+signals:
+	//当前行同步
+	void syncCurLineNum(int direction);
+
+	//滚动条同步
+	void syncCurScrollValue(int direction);
+
+	void syncCurScrollXValue(int direction);
+
+private:
+	//左右当前行的值
+	int m_leftLineNum;
+	int m_rightLineNum;
+
+	//左右滚动条的值
+	int m_leftScrollValue;
+	int m_rightScrollValue;
+
+	//左右滚动条的值x
+	int m_leftScrollXValue;
+	int m_rightScrollXValue;
+};
+

+ 58 - 0
MediatorFileTree.cpp

@@ -0,0 +1,58 @@
+#include "MediatorFileTree.h"
+
+/* 文件夹对比界面的中介者,使用中介者是为了让消息经过中介对象统一调度,避免左右互相依赖导致交互混乱
+*/
+
+MediatorFileTree::MediatorFileTree() :QObject(nullptr)
+{
+
+}
+
+MediatorFileTree::~MediatorFileTree()
+{
+
+}
+
+void MediatorFileTree::setLeftScrollValue(int value)
+{
+	m_leftScrollValue = value;
+
+	//如果左右不相等,则推动对方去同步
+	if (m_leftScrollValue != m_rightScrollValue)
+	{
+		emit syncCurScrollValue(0);
+	}
+
+}
+
+void MediatorFileTree::setRightScrollValue(int value)
+{
+	m_rightScrollValue = value;
+
+	if (m_leftScrollValue != m_rightScrollValue)
+	{
+		emit syncCurScrollValue(1);
+	}
+}
+
+int MediatorFileTree::getLeftScrollValue()
+{
+	return m_leftScrollValue;
+}
+
+int MediatorFileTree::getRightScrollValue()
+{
+	return m_rightScrollValue;
+}
+
+
+//设置item。中介本身不保存ITEM,因为太多,发送消息给外面空间
+void MediatorFileTree::setLeftItemStatus(QString name, int status)
+{
+	emit syncExpandStatus(name, RC_LEFT, status);
+}
+
+void MediatorFileTree::setRightItemStatus(QString name, int status)
+{
+	emit syncExpandStatus(name, RC_RIGHT, status);
+}

+ 32 - 0
MediatorFileTree.h

@@ -0,0 +1,32 @@
+#pragma once
+#include <qobject.h>
+#include "rcglobal.h"
+
+class MediatorFileTree :public QObject
+{
+	Q_OBJECT
+public:
+	MediatorFileTree();
+	virtual ~MediatorFileTree();
+
+	void setLeftScrollValue(int value);
+	void setRightScrollValue(int value);
+	int getLeftScrollValue();
+	int getRightScrollValue();
+
+	void setLeftItemStatus(QString name, int status);
+	void setRightItemStatus(QString name, int status);
+
+
+signals:
+	//滚动条同步
+	void syncCurScrollValue(int direction);
+
+	//同步展开和收起状态
+	void syncExpandStatus(QString name, int direction, int status);
+
+private:
+	int m_leftScrollValue;
+	int m_rightScrollValue;
+};
+

+ 138 - 0
QTreeWidgetSortItem.cpp

@@ -0,0 +1,138 @@
+#include "QTreeWidgetSortItem.h"
+#include "rcglobal.h"
+
+/* 自己重新实现一个QTreeWidgetSortItem,主要是为了重载函数的排序功能,不适应默认的名字排序,而是使用
+* 每个项自带的tip字符串排序。这样做是因为对齐的时候,有些空白对齐项目,并没有名称,就会导致无法排序
+*/
+int QTreeWidgetSortItem::s_sortType = 0;
+
+bool QTreeWidgetSortItem::s_syncOrder = false;
+
+QTreeWidgetSortItem::QTreeWidgetSortItem(int type):QTreeWidgetItem(type)
+{
+
+}
+
+QTreeWidgetSortItem::QTreeWidgetSortItem(const QStringList &strings, int type):QTreeWidgetItem(strings, type)
+{
+
+}
+
+QTreeWidgetSortItem::~QTreeWidgetSortItem()
+{
+
+}
+
+bool QTreeWidgetSortItem::operator<(const QTreeWidgetItem & other) const
+{
+	if (s_sortType == 0)
+	{
+		if (!s_syncOrder) //按名称排序
+		{
+	//目录最大,放在文件前面。都是目录则按照名称排序
+	if ((type() == RC_DIR) && (other.type() == RC_DIR))
+	{
+		goto cmp_name;
+	}
+	else if ((type() == RC_DIR) && (other.type() != RC_DIR))
+	{
+		return false;
+	}
+	else if ((type() != RC_DIR) && (other.type() == RC_DIR))
+	{
+		return true;
+	}
+
+cmp_name:
+
+	QString a = this->data(0, Item_RelativePath).toString();
+	QString b = other.data(0, Item_RelativePath).toString();
+
+			return (a.compare(b, Qt::CaseInsensitive) > 0);
+}
+		else
+		{
+			//同步序号,按序号进行排序
+#if 0
+			if ((type() == RC_DIR) && (other.type() == RC_DIR))
+			{
+				QString a = this->data(0, Item_RelativePath).toString();
+				QString b = other.data(0, Item_RelativePath).toString();
+
+				return !(a.compare(b, Qt::CaseInsensitive) > 0);
+			}
+			else if ((type() == RC_DIR) && (other.type() != RC_DIR))
+			{
+				return true;
+			}
+			else if ((type() != RC_DIR) && (other.type() == RC_DIR))
+			{
+				return false;
+			}
+
+		cmp_index:
+#endif
+			//同步对方的操作。
+			int a = this->data(0, Item_Index).toInt();
+			int b = other.data(0, Item_Index).toInt();
+
+			return(a > b);
+		}
+	}
+	else if (s_sortType == 1) //按大小排序
+	{
+		//目录最大,放在文件前面。都是目录则按照名称排序
+		if ((type() == RC_DIR) && (other.type() == RC_DIR))
+		{
+
+			qint64 a = this->data(0, DIR_ITEM_MAXSIZE_FILE).toULongLong();
+			qint64 b = other.data(0, DIR_ITEM_MAXSIZE_FILE).toULongLong(); 
+
+			return(a > b);
+#if 0
+			QString a = this->data(0, Item_RelativePath).toString();
+			QString b = other.data(0, Item_RelativePath).toString();
+
+			return (a.compare(b, Qt::CaseInsensitive) > 0);
+#endif
+		}
+		else if ((type() == RC_DIR) && (other.type() != RC_DIR))
+		{
+			return false;
+		}
+		else if ((type() != RC_DIR) && (other.type() == RC_DIR))
+		{
+			return true;
+		}
+
+		int leftSize = this->text(1).toInt();
+		int rightSize = other.text(1).toInt();
+
+		return(leftSize > rightSize);
+	}
+	else if (s_sortType == 2) //by 修改日期
+	{
+		//目录最大,放在文件前面。都是目录则按照名称排序
+		if ((type() == RC_DIR) && (other.type() == RC_DIR))
+		{
+			QString a = this->data(0, Item_RelativePath).toString();
+			QString b = other.data(0, Item_RelativePath).toString();
+
+			return (a.compare(b, Qt::CaseInsensitive) > 0);
+		}
+		else if ((type() == RC_DIR) && (other.type() != RC_DIR))
+		{
+			return false;
+		}
+		else if ((type() != RC_DIR) && (other.type() == RC_DIR))
+		{
+			return true;
+		}
+
+		QString a = this->text(2);
+		QString b = other.text(2);
+
+		return(a.compare(b, Qt::CaseInsensitive) > 0);
+	}
+	return false;
+}

+ 23 - 0
QTreeWidgetSortItem.h

@@ -0,0 +1,23 @@
+#pragma once
+#include <qtreewidget.h>
+class QTreeWidgetSortItem : public QTreeWidgetItem
+{
+public:
+	QTreeWidgetSortItem(int type);
+	QTreeWidgetSortItem(const QStringList &strings, int type);
+	virtual ~QTreeWidgetSortItem();
+	virtual bool operator<(const QTreeWidgetItem &other) const override;
+
+	static void setSortColumn(int index)
+	{
+		s_sortType = index;
+	}
+	static void setSyncOrder(bool v)
+	{
+		s_syncOrder = v;
+	}
+private :
+	static int s_sortType;
+	static bool s_syncOrder;
+};
+

+ 158 - 0
RcTreeWidget.cpp

@@ -0,0 +1,158 @@
+#include "RcTreeWidget.h"
+#include "MediatorFileTree.h"
+
+#include <QScrollBar>
+#include <QMenu>
+#include <QProcess>
+
+RcTreeWidget::RcTreeWidget(QWidget *parent):QTreeWidget(parent), m_userAddMenu(nullptr)
+{
+
+	connect(this->verticalScrollBar(), &QScrollBar::valueChanged, this, &RcTreeWidget::slot_scrollValueChange);
+
+	//收起和伸开子项
+	connect(this, &QTreeWidget::itemCollapsed, this, &RcTreeWidget::slot_itemCollapsed);
+	connect(this, &QTreeWidget::itemExpanded, this, &RcTreeWidget::slot_itemExpanded);
+
+	setContextMenuPolicy(Qt::CustomContextMenu);  //设置枚举值
+	connect(this, &QTreeWidget::customContextMenuRequested, this, &RcTreeWidget::slot_ShowPopMenu);
+}
+
+RcTreeWidget::~RcTreeWidget()
+{
+
+}
+
+//给用户进行菜单增加的回调函数
+void RcTreeWidget::setContextUserDefineItemMenuCallBack(std::function<void(int dire,QMenu*, QTreeWidgetItem*)>* userAddMenu)
+{
+	m_userAddMenu = userAddMenu;
+}
+
+
+//右键菜单
+void RcTreeWidget::slot_ShowPopMenu(const QPoint& pos)
+{
+	QTreeWidgetItem* curItem = this->itemAt(pos);
+	if (curItem != nullptr)
+	{
+		
+		QMenu* menu = new QMenu(this);
+
+		if (m_userAddMenu != nullptr)
+		{
+			(*m_userAddMenu)(m_direction, menu, curItem);
+		}
+
+		QAction* action = menu->addAction(tr("Show File in Explorer"), this, [&]() {
+			QString path, cmd;
+
+			path = QString("%1/%2").arg(m_rootDir).arg(curItem->data(0, Qt::ToolTipRole).toString());
+			#ifdef _WIN32
+				path = path.replace("/", "\\");
+				cmd = QString("explorer.exe /select,%1").arg(path);
+			#else
+				path = path.replace("\\", "/");
+				cmd = QString("open -R %1").arg(path);
+			#endif
+				QProcess process;
+				process.startDetached(cmd);
+			});
+
+		//没有名称表示是对齐的item,不存在对应的文件,只是占位
+		if (curItem->text(0).isEmpty())
+		{
+			action->setEnabled(false);
+		}
+
+		if (menu)
+		{
+			menu->setAttribute(Qt::WA_DeleteOnClose);
+			menu->exec(QCursor::pos());
+		}
+	}
+}
+
+
+//点击收起的槽函数
+void RcTreeWidget::slot_itemCollapsed(QTreeWidgetItem *item)
+{
+	QString name = item->data(0, Qt::ToolTipRole).toString();
+	//左边变化,通知右边去改变
+	if (m_direction == RC_LEFT)
+	{
+		//通知右边去收起
+		m_mediator->setRightItemStatus(name,RC_COLLAPSED);
+	}
+	else
+	{
+		//通知左边去收起
+		m_mediator->setLeftItemStatus(name, RC_COLLAPSED);
+	}
+}
+
+//点击展开的槽函数
+void RcTreeWidget::slot_itemExpanded(QTreeWidgetItem *item)
+{
+	QString name = item->data(0, Qt::ToolTipRole).toString();
+
+	//左边变化,通知右边去改变
+	if (m_direction == RC_LEFT)
+	{
+		//右边展开
+		m_mediator->setRightItemStatus(name, RC_EXPANDED);
+	}
+	else
+	{
+		//左边收起
+		m_mediator->setLeftItemStatus(name, RC_EXPANDED);
+	}
+}
+
+void RcTreeWidget::setDirection(RC_DIRECTION direction)
+{
+	m_direction = direction;
+}
+
+void RcTreeWidget::setMediator(MediatorFileTree *mediator)
+{
+	m_mediator = mediator;
+
+}
+
+//滚动条值变化后的槽函数。一旦滚动则会出发这里,发送消息给中介,让中介去同步另外一方
+void RcTreeWidget::slot_scrollValueChange(int value)
+{
+	if (m_direction == RC_LEFT)
+	{
+		if (m_mediator->getLeftScrollValue() != value)
+		{
+			m_mediator->setLeftScrollValue(value);
+		}
+	}
+	else
+	{
+		if (m_mediator->getRightScrollValue() != value)
+		{
+			m_mediator->setRightScrollValue(value);
+		}
+	}
+}
+
+//注意,这里一旦开始调整后,又会引发滚动条值的变化
+void RcTreeWidget::setVerticalValue(int value)
+{
+	//不相等才需要设置
+	if (verticalScrollBar()->value() != value)
+	{
+		//超过最大值,只能设置为最大值
+		if (value > verticalScrollBar()->maximum())
+		{
+			verticalScrollBar()->setValue(verticalScrollBar()->maximum());
+		}
+		else
+		{
+			verticalScrollBar()->setValue(value);
+		}
+	}
+}

+ 46 - 0
RcTreeWidget.h

@@ -0,0 +1,46 @@
+#pragma once
+#include <qtreewidget.h>
+#include <QPoint>
+#include <functional>
+#include <QMenu>
+
+#include "rcglobal.h"
+
+class MediatorFileTree;
+
+class RcTreeWidget :public QTreeWidget
+{
+	
+public:
+	RcTreeWidget(QWidget *parent=nullptr);
+	~RcTreeWidget();
+
+	void setContextUserDefineItemMenuCallBack(std::function<void(int dire, QMenu*, QTreeWidgetItem*)>* userAddMenu);
+
+	void setDirection(RC_DIRECTION direction);
+	void setMediator(MediatorFileTree * mediator);
+	void setVerticalValue(int value);
+
+	void setRootDir(QString dir)
+	{
+		m_rootDir = dir;
+	}
+
+	QString getRootDir()
+	{
+		return m_rootDir;
+	}
+
+public slots:
+	void slot_scrollValueChange(int value);
+	void slot_itemCollapsed(QTreeWidgetItem * item);
+	void slot_itemExpanded(QTreeWidgetItem * item);
+	void slot_ShowPopMenu(const QPoint& pos);
+private:
+	MediatorFileTree * m_mediator;
+	RC_DIRECTION m_direction;
+	QString m_rootDir;
+
+	std::function<void(int dire, QMenu*, QTreeWidgetItem*)>* m_userAddMenu;
+};
+

+ 18 - 0
RealCompare.pri

@@ -0,0 +1,18 @@
+# ----------------------------------------------------
+# This file is generated by the Qt Visual Studio Tools.
+# ------------------------------------------------------
+
+# This is a reminder that you are using a generated .pro file.
+# Remove it when you are finished editing this file.
+message("You are running qmake on a generated .pro file. This may not work!")
+
+
+HEADERS += ./RealCompare.h \
+    $$PWD/diff.h \
+    ./CompareWin.h
+SOURCES += ./CompareWin.cpp \
+    ./main.cpp \
+    ./RealCompare.cpp
+FORMS += ./CompareWin.ui \
+    ./RealCompare.ui
+RESOURCES += RealCompare.qrc

+ 84 - 0
RealCompare.pro

@@ -0,0 +1,84 @@
+TEMPLATE = app
+LANGUAGE = C++
+
+TARGET = Notepad--
+
+CONFIG	+= qt warn_on release
+
+QT += core gui widgets concurrent network
+
+
+HEADERS	+= *.h \
+        cceditor/ccnotepad.h \
+        cceditor/filemanager.h
+
+		
+SOURCES	+= *.cpp *.cc \
+                cceditor/ccnotepad.cpp \
+                cceditor/filemanager.cpp
+
+		
+FORMS += *.ui \
+                cceditor/ccnotepad.ui
+
+
+RESOURCES += RealCompare.qrc
+
+INCLUDEPATH	+= qscint/src
+INCLUDEPATH	+= qscint/src/Qsci
+INCLUDEPATH	+= qscint/scintilla/include
+INCLUDEPATH += cceditor
+
+DEFINES +=  QSCINTILLA_DLL
+
+TRANSLATIONS += realcompare_zh.ts
+	
+win32 {
+   if(contains(QMAKE_HOST.arch, x86_64)){
+    CONFIG(Debug, Debug|Release){
+        DESTDIR = x64/Debug
+		LIBS	+= -Lx64/Debug
+		LIBS += -lqmyedit_qt5d
+    }else{
+        DESTDIR = x64/Release
+		LIBS	+= -Lx64/Release
+		LIBS += -lqmyedit_qt5
+                QMAKE_CXXFLAGS += /openmp
+    }
+   }
+}
+unix{
+if(CONFIG(debug, debug|release)){
+          LIBS += -L/home/yzw/build/CCNotePad/lib -lprotobuf
+          LIBS += -L/home/yzw/build/CCNotePad/x64/Debug -lqmyedit_qt5
+
+QMAKE_CXXFLAGS += -fopenmp
+LIBS += -lgomp -lpthread
+    }else{
+          LIBS += -L/home/yzw/build/CCNotePad/lib -lprotobuf
+          LIBS += -L/home/yzw/build/CCNotePad/x64/Release -lqmyedit_qt5
+        DESTDIR = x64/Release
+
+        QMAKE_CXXFLAGS += -fopenmp -O2
+        LIBS += -lgomp -lpthread
+    }
+   }
+
+
+RC_FILE += RealCompare.rc
+unix
+{
+unix:!macx: LIBS += -L$$PWD/lib/ -lprotobuf
+
+INCLUDEPATH += $$PWD/.
+DEPENDPATH += $$PWD/.
+
+unix:!macx: PRE_TARGETDEPS += $$PWD/lib/libprotobuf.a
+
+unix:!macx: LIBS += -L$$PWD/x64/Release/ -lqmyedit_qt5
+
+INCLUDEPATH += $$PWD/x64/Release
+DEPENDPATH += $$PWD/x64/Release
+
+unix:!macx: PRE_TARGETDEPS += $$PWD/x64/Release/libqmyedit_qt5.a
+}

+ 156 - 0
RealCompare.qrc

@@ -0,0 +1,156 @@
+<RCC>
+    <qresource prefix="/">
+        <file>Resources/img/dir.png</file>
+        <file>Resources/img/file.png</file>
+        <file>Resources/img/open.png</file>
+        <file>Resources/img/open1.png</file>
+        <file>Resources/img/save.png</file>
+        <file>Resources/img/all.png</file>
+        <file>Resources/img/same1.png</file>
+        <file>Resources/img/diff1.png</file>
+        <file>Resources/img/swap.png</file>
+        <file>Resources/img/reload.png</file>
+        <file>Resources/img/rule.png</file>
+        <file>Resources/img/left3.png</file>
+        <file>Resources/img/right3.png</file>
+        <file>Resources/img/point.png</file>
+        <file>Resources/img/main.png</file>
+        <file>Resources/img/showchar.png</file>
+        <file>Resources/img/hidechar.png</file>
+        <file>Resources/img/reload2.png</file>
+        <file>Resources/img/tran.png</file>
+        <file>Resources/img/6688.png</file>
+        <file>Resources/img/clear.png</file>
+        <file>Resources/img/undo.png</file>
+        <file>Resources/img/redo.png</file>
+        <file>Resources/edit/global/close.png</file>
+        <file>Resources/edit/global/closehover.png</file>
+        <file>Resources/edit/global/needsave.png</file>
+        <file>Resources/edit/global/noneedsave.png</file>
+        <file>Resources/edit/styleblack/closeall.png</file>
+        <file>Resources/edit/styleblack/closefile.png</file>
+        <file>Resources/edit/styleblack/crlf.png</file>
+        <file>Resources/edit/styleblack/cut.png</file>
+        <file>Resources/edit/styleblack/dircompare.png</file>
+        <file>Resources/edit/styleblack/filecompare.png</file>
+        <file>Resources/edit/styleblack/find.png</file>
+        <file>Resources/edit/styleblack/needsavebar.png</file>
+        <file>Resources/edit/styleblack/newfile.png</file>
+        <file>Resources/edit/styleblack/noneedsaveallbar.png</file>
+        <file>Resources/edit/styleblack/noneedsavebar.png</file>
+        <file>Resources/edit/styleblack/openfile.png</file>
+        <file>Resources/edit/styleblack/paste.png</file>
+        <file>Resources/edit/styleblack/redo.png</file>
+        <file>Resources/edit/styleblack/replace.png</file>
+        <file>Resources/edit/styleblack/transcode.png</file>
+        <file>Resources/edit/styleblack/undo.png</file>
+        <file>Resources/edit/styleblack/white.png</file>
+        <file>Resources/edit/styleblack/zoomin.png</file>
+        <file>Resources/edit/styleblack/zoomout.png</file>
+        <file>Resources/edit/styleblack/copy.png</file>
+        <file>Resources/edit/styleblack/needsaveallbar.png</file>
+        <file>Resources/edit/styledeepblue/closeall.png</file>
+        <file>Resources/edit/styledeepblue/closefile.png</file>
+        <file>Resources/edit/styledeepblue/copy.png</file>
+        <file>Resources/edit/styledeepblue/crlf.png</file>
+        <file>Resources/edit/styledeepblue/cut.png</file>
+        <file>Resources/edit/styledeepblue/dircompare.png</file>
+        <file>Resources/edit/styledeepblue/filecompare.png</file>
+        <file>Resources/edit/styledeepblue/find.png</file>
+        <file>Resources/edit/styledeepblue/needsaveallbar.png</file>
+        <file>Resources/edit/styledeepblue/needsavebar.png</file>
+        <file>Resources/edit/styledeepblue/newfile.png</file>
+        <file>Resources/edit/styledeepblue/noneedsaveallbar.png</file>
+        <file>Resources/edit/styledeepblue/noneedsavebar.png</file>
+        <file>Resources/edit/styledeepblue/openfile.png</file>
+        <file>Resources/edit/styledeepblue/paste.png</file>
+        <file>Resources/edit/styledeepblue/redo.png</file>
+        <file>Resources/edit/styledeepblue/replace.png</file>
+        <file>Resources/edit/styledeepblue/transcode.png</file>
+        <file>Resources/edit/styledeepblue/undo.png</file>
+        <file>Resources/edit/styledeepblue/white.png</file>
+        <file>Resources/edit/styledeepblue/zoomin.png</file>
+        <file>Resources/edit/styledeepblue/zoomout.png</file>
+        <file>Resources/edit/global/notebook.png</file>
+        <file>Resources/img/next.png</file>
+        <file>Resources/img/pre.png</file>
+        <file>Resources/edit/styledeepblue/rename.png</file>
+        <file>realcompare_zh.qm</file>
+        <file>Resources/edit/styleblack/rename.png</file>
+        <file>Resources/img/bin.png</file>
+        <file>Resources/img/info.png</file>
+        <file>Resources/edit/styledeepblue/next.png</file>
+        <file>Resources/edit/styledeepblue/pre.png</file>
+        <file>Resources/edit/styledeepblue/goto.png</file>
+        <file>Resources/edit/styledeepblue/bincmp.png</file>
+        <file>Resources/img/strict.png</file>
+        <file>Resources/img/1.png</file>
+        <file>Resources/img/2.png</file>
+        <file>Resources/img/3.png</file>
+        <file>Resources/img/4.png</file>
+        <file>Resources/img/5.png</file>
+        <file>Resources/img/6.png</file>
+        <file>Resources/img/next2.png</file>
+        <file>Resources/img/pre2.png</file>
+        <file>Resources/img/zoomin.png</file>
+        <file>Resources/img/zoomout.png</file>
+        <file>Resources/img/unequaldir.png</file>
+        <file>Resources/img/unequalfile.png</file>
+        <file>Resources/img/onlyfile.png</file>
+        <file>Resources/img/showall.png</file>
+        <file>Resources/img/diff.png</file>
+        <file>Resources/img/tolerant.png</file>
+        <file>Resources/img/needsave.png</file>
+        <file>Resources/img/break.png</file>
+        <file>Resources/img/pullopen.png</file>
+        <file>notepad/closeAll.png</file>
+        <file>notepad/closeFile.png</file>
+        <file>notepad/closeTabButton.png</file>
+        <file>notepad/closeTabButton_hover.png</file>
+        <file>notepad/closeTabButton_inact.png</file>
+        <file>notepad/closeTabButton_push.png</file>
+        <file>notepad/copy.png</file>
+        <file>notepad/cut.png</file>
+        <file>notepad/find.png</file>
+        <file>notepad/findReplace.png</file>
+        <file>notepad/indentGuide.png</file>
+        <file>notepad/invisibleChar.png</file>
+        <file>notepad/newFile.png</file>
+        <file>notepad/openFile.png</file>
+        <file>notepad/paste.png</file>
+        <file>notepad/redo.png</file>
+        <file>notepad/saveAll.png</file>
+        <file>notepad/saveFile.png</file>
+        <file>notepad/undo.png</file>
+        <file>notepad/wrap.png</file>
+        <file>notepad/zoomIn.png</file>
+        <file>notepad/zoomOut.png</file>
+        <file>notepad/savetab.png</file>
+        <file>notepad/close.png</file>
+        <file>notepad/closehover.png</file>
+        <file>notepad/cmpbin.png</file>
+        <file>notepad/cmpdir.png</file>
+        <file>notepad/cmpfile.png</file>
+        <file>notepad/cmpfile1.png</file>
+        <file>notepad/ecg.png</file>
+        <file>notepad/go.png</file>
+        <file>notepad/needsave.png</file>
+        <file>notepad/next.png</file>
+        <file>notepad/noneedsave.png</file>
+        <file>notepad/pre.png</file>
+        <file>notepad/rename.png</file>
+        <file>Resources/edit/global/ndd.ico</file>
+        <file>notepad/mark.png</file>
+        <file>notepad/sign.png</file>
+        <file>notepad/clearsign.png</file>
+        <file>notepad/autosave.png</file>
+        <file>qss/lightblue/arrow_bottom.png</file>
+        <file>qss/lightblue/add_bottom.png</file>
+        <file>qss/mystyle.qss</file>
+        <file>qss/lightbluestyle.qss</file>
+        <file>qss/lightblue/add_top.png</file>
+        <file>mac.icns</file>
+        <file>Resources/img/register.png</file>
+        <file>notepad/rightClose.png</file>
+    </qresource>
+</RCC>

BIN
RealCompare.rc


BIN
Resources/1.png


BIN
Resources/2.png


BIN
Resources/3.png


BIN
Resources/4.png


BIN
Resources/edit/global/book32.ico


BIN
Resources/edit/global/book64.ico


BIN
Resources/edit/global/close.png


BIN
Resources/edit/global/closehover.png


File diff suppressed because it is too large
+ 0 - 0
Resources/edit/global/export-2022-06-30 061114.svg


BIN
Resources/edit/global/main128.ico


BIN
Resources/edit/global/main32.ico


BIN
Resources/edit/global/main64.ico


BIN
Resources/edit/global/ndd.ico


BIN
Resources/edit/global/ndd.png


+ 2 - 0
Resources/edit/global/ndd.svg

@@ -0,0 +1,2 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1653643519286" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8215" width="48" height="48" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
+</style></defs><path d="M648.479968 0.00064h-511.99968A48.959969 48.959969 0 0 0 100.64031 15.36063 54.399966 54.399966 0 0 0 85.28032 51.200608v921.599424a48.959969 48.959969 0 0 0 15.35999 35.839978A50.559968 50.559968 0 0 0 136.480288 1024h751.039531a49.279969 49.279969 0 0 0 35.839977-15.35999 50.559968 50.559968 0 0 0 15.359991-35.839978V290.240459z" fill="#A5D940" p-id="8216"></path><path d="M938.719787 290.240459H699.679936a52.479967 52.479967 0 0 1-51.199968-51.199968V0.00064l290.239819 290.239819z" fill="#C4EAFF" p-id="8217"></path><path d="M407.520119 459.520353v29.759981H331.360166v198.719876H296.800188v-198.719876H220.320236v-29.759981zM462.240084 459.520353l55.679966 82.559948 55.679965-82.559948h42.559973l-77.439951 110.399931 82.879948 118.079926h-42.559974l-61.119961-90.559943-61.119962 90.559943h-42.559974l82.239949-118.079926-76.799952-110.399931zM815.199864 459.520353v29.759981h-76.159953v198.719876h-34.559978v-198.719876H629.27998v-29.759981z" fill="#FFFFFF" p-id="8218"></path></svg>

BIN
Resources/edit/global/ndd1.ico


BIN
Resources/edit/global/ndd2.ico


BIN
Resources/edit/global/ndd4.ico


BIN
Resources/edit/global/ndd_old.ico


BIN
Resources/edit/global/ndd_old.png


BIN
Resources/edit/global/needsave.png


BIN
Resources/edit/global/noneedsave.png


BIN
Resources/edit/global/notebook.png


BIN
Resources/edit/global/notebook128.ico


+ 20 - 0
Resources/edit/global/notepad.svg

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">  <image id="image0" width="16" height="16" x="0" y="0"
+    href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJN
+AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAABX1BMVEUAAACgpKDQ1NDAxc/P
+zs/AxMCwwLCfoJCfop/AmI+vh4+Ql5Dg6ODg4uDg5+/Q2N/Q2tCgr6+wn6DAoJ+PaHCQmJDAv8C/
+v7+wv6+gr7+gp7/w9//Qz9DAr5/fx5D/+M+fkIDPx8+fnJ/w9PC/t7+wt6/P0MDAx9+vqL+gn5+w
+qJC/oEDw31+/r0/AyLDf3d/v9ODw/P//9///9/D/8MDfz3/v0DDgyE/Av3/QyLDAt2DfyEDv0CCf
+gEDw5+Dw9O+gqKDPz8DAt8/Qt9DfsH/gxyDgwBCQkH/f3M+/t7D//P/g39/f0NDgwJ/fuC+ggEC/
+v6/v79/QzM/P1M/Q2ODAwKDQwC+vkEDQyMCwqGDg2DCvly//6O/w/fD///Df0M/At2+voF/v4NDQ
+4NDf3OBfT0Dg3+Dv7e+Pj4///+/g5/Dv6OD/8ODg9/Dv/++vr6+Ah4BweHBwdXBvbG////8Y2q+X
+AAAAAXRSTlMAQObYZgAAAAFiS0dEdN9tqG0AAAAHdElNRQfmBRsIAQRTVKkxAAAA+klEQVQY0y2L
+Z1PCQBRFH5tsRCEaC6KuWPLErgmo2NDYxWcHuwYbmlgJ8P9nzM54v90z50CEMUXlWlMU5JpbIBbX
+W9sMjbez8Hd0dkFC17qTPVpvn+hPDQwODYOJyZH0KB8bn5icmp6ZhRBYum5nsnPzC7nFpTCLIrOY
+wZTlldX82noITGeDs82t7Z3dvf3CQQgixA85Ozo+yZ2encdkQmqxdHF5lb++KdgSmKgWmXJ7d//g
+OmVVlYnjZh+fnl+E7SDGpGG8Vt5S71j2BJIvjTh+0Gfli4gEpSXwvsXPr0uYIeGWAKpI6Fm8avpB
+rVZPAPhBo1EPTA3+9wcoICtzAO/bXwAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMi0wNS0yN1QwODow
+MTowNCswMDowMHQN1joAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjItMDUtMjdUMDg6MDE6MDQrMDA6
+MDAFUG6GAAAAAElFTkSuQmCC" />
+</svg>

+ 2 - 0
Resources/edit/global/txt.svg

@@ -0,0 +1,2 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1655351318268" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8004" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
+</style></defs><path d="M192 0h448.1536L960 320v576c0 70.6944-57.3056 128-128 128H192C121.3056 1024 64 966.6944 64 896V128C64 57.3056 121.3056 0 192 0z" fill="#2696FF" p-id="8005"></path><path d="M417.7536 546.176h-60.8256v170.5728h-40.9216V546.176H256V512h161.7536v34.176z m94.3872 36.416L549.376 512h47.0528l-57.8304 101.5296 59.328 103.2192h-47.6032l-38.1824-71.7184-38.1952 71.7184h-47.6032l59.3408-103.2192L427.8528 512h47.0528l37.2352 70.592zM768 546.176h-60.8256v170.5728H666.24V546.176h-60.0064V512H768v34.176z" fill="#FFFFFF" opacity=".9" p-id="8006"></path><path d="M640 0l320 320H768c-70.6944 0-128-57.3056-128-128V0z" fill="#8FC6FE" p-id="8007"></path></svg>

+ 2 - 0
Resources/edit/global/txt1.svg

@@ -0,0 +1,2 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1655351271993" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3721" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
+</style></defs><path d="M147.2 0C102.4 0 65.6 35.2 65.6 80v862.4c0 44.8 35.2 81.6 81.6 81.6h731.2c44.8 0 81.6-36.8 81.6-81.6V324.8L657.6 0H147.2z" fill="#F9CA06" p-id="3722"></path><path d="M960 324.8v16H755.2s-100.8-19.2-97.6-107.2c0 0 3.2 91.2 96 91.2H960z" fill="#F7BC04" p-id="3723"></path><path d="M657.6 0v232c0 27.2 17.6 92.8 97.6 92.8H960L657.6 0z" fill="#FFFFFF" p-id="3724"></path><path d="M364.8 688h-52.8v161.6c0 6.4-4.8 11.2-12.8 11.2-6.4 0-11.2-4.8-11.2-11.2V688h-52.8c-4.8 0-9.6-3.2-9.6-9.6 0-6.4 4.8-11.2 9.6-11.2h129.6c4.8 0 9.6 4.8 9.6 11.2 0 6.4-4.8 9.6-9.6 9.6z m187.2 172.8c-4.8 0-8 0-9.6-3.2l-59.2-80-60.8 80c-1.6 3.2-4.8 3.2-8 3.2-6.4 0-11.2-4.8-11.2-11.2 0-1.6 0-4.8 1.6-6.4l62.4-81.6-57.6-78.4c-1.6-1.6-1.6-3.2-1.6-6.4 0-4.8 3.2-11.2 11.2-11.2 3.2 0 6.4 1.6 9.6 4.8l54.4 73.6 54.4-73.6c3.2-3.2 6.4-4.8 9.6-4.8 6.4 0 11.2 4.8 11.2 11.2 0 3.2 0 4.8-1.6 6.4l-57.6 76.8 62.4 83.2c0 1.6 1.6 4.8 1.6 6.4 0 6.4-4.8 11.2-11.2 11.2zM731.2 688h-52.8v161.6c0 6.4-4.8 11.2-12.8 11.2-6.4 0-11.2-4.8-11.2-11.2V688h-52.8c-4.8 0-9.6-3.2-9.6-9.6 0-6.4 4.8-11.2 9.6-11.2h129.6c4.8 0 9.6 4.8 9.6 11.2 0 6.4-4.8 9.6-9.6 9.6z" fill="#FFFFFF" p-id="3725"></path></svg>

BIN
Resources/edit/global/wizard_GiletJaune.jpg


BIN
Resources/edit/global/wizard_GiletJaune1.jpg


BIN
Resources/edit/styleblack/308上一页、后退、返回.png


BIN
Resources/edit/styleblack/closeall.png


BIN
Resources/edit/styleblack/closefile.png


BIN
Resources/edit/styleblack/closefile2.png


BIN
Resources/edit/styleblack/copy.png


BIN
Resources/edit/styleblack/crlf.png


BIN
Resources/edit/styleblack/cut.png


BIN
Resources/edit/styleblack/dircompare.png


BIN
Resources/edit/styleblack/filecompare.png


BIN
Resources/edit/styleblack/find.png


BIN
Resources/edit/styleblack/find2.png


BIN
Resources/edit/styleblack/jhym_goto (1).png


BIN
Resources/edit/styleblack/needsaveallbar.png


BIN
Resources/edit/styleblack/needsavebar.png


BIN
Resources/edit/styleblack/newfile.png


BIN
Resources/edit/styleblack/noneedsaveallbar.png


BIN
Resources/edit/styleblack/noneedsavebar.png


BIN
Resources/edit/styleblack/openfile.png


BIN
Resources/edit/styleblack/openfile3.png


BIN
Resources/edit/styleblack/paste.png


BIN
Resources/edit/styleblack/redo.png


BIN
Resources/edit/styleblack/redo2.png


BIN
Resources/edit/styleblack/rename.png


BIN
Resources/edit/styleblack/rename1.png


BIN
Resources/edit/styleblack/replace.png


BIN
Resources/edit/styleblack/replace2.png


BIN
Resources/edit/styleblack/replace3.png


BIN
Resources/edit/styleblack/replace4.png


BIN
Resources/edit/styleblack/save (13).png


BIN
Resources/edit/styleblack/save (8).png


BIN
Resources/edit/styleblack/save-all.png


BIN
Resources/edit/styleblack/save_all.png


BIN
Resources/edit/styleblack/transcode.png


BIN
Resources/edit/styleblack/undo.png


BIN
Resources/edit/styleblack/white.png


BIN
Resources/edit/styleblack/white2.png


BIN
Resources/edit/styleblack/zoomin.png


BIN
Resources/edit/styleblack/zoomout.png


BIN
Resources/edit/styleblack/下一页 (2).png


BIN
Resources/edit/styleblack/保存 (7).png


BIN
Resources/edit/styleblack/保存 (8).png


BIN
Resources/edit/styleblack/关闭 (4).png


BIN
Resources/edit/styleblack/关闭 (6).png


BIN
Resources/edit/styleblack/关闭 (8).png


BIN
Resources/edit/styleblack/关闭 (9).png


BIN
Resources/edit/styleblack/关闭所有 (4).png


BIN
Resources/edit/styleblack/关闭所有_x (1).png


BIN
Resources/edit/styleblack/右箭头 (1).png


BIN
Resources/edit/styleblack/对比 (1).png


BIN
Resources/edit/styleblack/对比度 (1).png


BIN
Resources/edit/styleblack/对比度 (2).png


BIN
Resources/edit/styleblack/左箭头 (1).png


BIN
Resources/edit/styleblack/新建 (5).png


BIN
Resources/edit/styleblack/新建文件 (1).png


BIN
Resources/edit/styleblue/Clipboard Paste (2).png


Some files were not shown because too many files changed in this diff