소스 검색

一次性整体提交v2.0的代码;基础版功能全部提交完毕。

爬山虎 2 년 전
부모
커밋
9ac0a01a2d
100개의 변경된 파일1975개의 추가작업 그리고 976개의 파일을 삭제
  1. 60 3
      src/CmpareMode.cpp
  2. 2 1
      src/CmpareMode.h
  3. BIN
      src/RealCompare.rc
  4. BIN
      src/Resources/edit/global/ndd.ico
  5. BIN
      src/Resources/edit/styledark/mark.png
  6. 357 71
      src/cceditor/ccnotepad.cpp
  7. 22 5
      src/cceditor/ccnotepad.h
  8. 3 0
      src/cceditor/ccnotepad.ui
  9. 263 101
      src/cceditor/filemanager.cpp
  10. 6 3
      src/cceditor/filemanager.h
  11. 1 1
      src/columnedit.ui
  12. 10 1
      src/ctipwin.cpp
  13. 1 1
      src/ctipwin.h
  14. 26 2
      src/dectfilechanges.cpp
  15. 9 0
      src/dectfilechanges.h
  16. 4 2
      src/encodeconvert.cpp
  17. 288 0
      src/findresultview.cpp
  18. 49 0
      src/findresultview.h
  19. 190 458
      src/findresultwin.cpp
  20. 17 20
      src/findresultwin.h
  21. 8 25
      src/findresultwin.ui
  22. 233 55
      src/findwin.cpp
  23. 9 1
      src/findwin.h
  24. 80 55
      src/findwin.ui
  25. 6 2
      src/main.cpp
  26. 18 0
      src/markdownview.cpp
  27. 17 0
      src/markdownview.h
  28. 65 0
      src/markdownview.ui
  29. 25 0
      src/nddpluginapi.cpp
  30. 37 0
      src/nddpluginapi.h
  31. 17 2
      src/nddsetting.cpp
  32. 6 0
      src/nddsetting.h
  33. 0 62
      src/ndstyleditemdelegate.cpp
  34. 1 1
      src/plugin.h
  35. 1 1
      src/plugin/helloworld/helloworld.pro
  36. 32 3
      src/plugin/helloworld/helloworldexport.cpp
  37. 10 5
      src/plugin/test/test.cpp
  38. 7 1
      src/qscint/scintilla/src/EditView.cpp
  39. 1 1
      src/qscint/scintilla/src/Editor.cpp
  40. 11 11
      src/qscint/src/InputMethod.cpp
  41. 2 2
      src/qscint/src/ListBoxQt.cpp
  42. 2 2
      src/qscint/src/ListBoxQt.h
  43. 2 2
      src/qscint/src/MacPasteboardMime.cpp
  44. 2 2
      src/qscint/src/PlatQt.cpp
  45. 2 2
      src/qscint/src/Qsci/qsciabstractapis.h
  46. 2 2
      src/qscint/src/Qsci/qsciapis.h
  47. 2 2
      src/qscint/src/Qsci/qscicommand.h
  48. 2 2
      src/qscint/src/Qsci/qscicommandset.h
  49. 2 2
      src/qscint/src/Qsci/qscidocument.h
  50. 2 1
      src/qscint/src/Qsci/qsciglobal.h
  51. 1 1
      src/qscint/src/Qsci/qscilexer.h
  52. 2 2
      src/qscint/src/Qsci/qscilexerasm.h
  53. 1 1
      src/qscint/src/Qsci/qscilexeravs.h
  54. 1 1
      src/qscint/src/Qsci/qscilexerbash.h
  55. 1 1
      src/qscint/src/Qsci/qscilexerbatch.h
  56. 1 1
      src/qscint/src/Qsci/qscilexercmake.h
  57. 1 1
      src/qscint/src/Qsci/qscilexercoffeescript.h
  58. 1 1
      src/qscint/src/Qsci/qscilexercpp.h
  59. 1 1
      src/qscint/src/Qsci/qscilexercsharp.h
  60. 1 1
      src/qscint/src/Qsci/qscilexercss.h
  61. 2 2
      src/qscint/src/Qsci/qscilexercustom.h
  62. 1 1
      src/qscint/src/Qsci/qscilexerd.h
  63. 2 2
      src/qscint/src/Qsci/qscilexerdiff.h
  64. 2 2
      src/qscint/src/Qsci/qscilexeredifact.h
  65. 1 1
      src/qscint/src/Qsci/qscilexerfortran.h
  66. 1 1
      src/qscint/src/Qsci/qscilexerfortran77.h
  67. 1 1
      src/qscint/src/Qsci/qscilexergo.h
  68. 1 1
      src/qscint/src/Qsci/qscilexerhtml.h
  69. 1 1
      src/qscint/src/Qsci/qscilexeridl.h
  70. 1 1
      src/qscint/src/Qsci/qscilexerjava.h
  71. 1 1
      src/qscint/src/Qsci/qscilexerjavascript.h
  72. 1 1
      src/qscint/src/Qsci/qscilexerjson.h
  73. 1 1
      src/qscint/src/Qsci/qscilexerlua.h
  74. 2 2
      src/qscint/src/Qsci/qscilexermakefile.h
  75. 2 2
      src/qscint/src/Qsci/qscilexermarkdown.h
  76. 1 1
      src/qscint/src/Qsci/qscilexermatlab.h
  77. 1 1
      src/qscint/src/Qsci/qscilexeroctave.h
  78. 1 1
      src/qscint/src/Qsci/qscilexerpascal.h
  79. 1 1
      src/qscint/src/Qsci/qscilexerperl.h
  80. 2 2
      src/qscint/src/Qsci/qscilexerpo.h
  81. 1 1
      src/qscint/src/Qsci/qscilexerpostscript.h
  82. 1 1
      src/qscint/src/Qsci/qscilexerpov.h
  83. 2 2
      src/qscint/src/Qsci/qscilexerproperties.h
  84. 1 1
      src/qscint/src/Qsci/qscilexerpython.h
  85. 2 2
      src/qscint/src/Qsci/qscilexerr.h
  86. 1 1
      src/qscint/src/Qsci/qscilexerruby.h
  87. 1 1
      src/qscint/src/Qsci/qscilexerspice.h
  88. 1 1
      src/qscint/src/Qsci/qscilexersql.h
  89. 1 1
      src/qscint/src/Qsci/qscilexertcl.h
  90. 1 1
      src/qscint/src/Qsci/qscilexertex.h
  91. 1 1
      src/qscint/src/Qsci/qscilexerverilog.h
  92. 1 1
      src/qscint/src/Qsci/qscilexervhdl.h
  93. 1 1
      src/qscint/src/Qsci/qscilexerxml.h
  94. 1 1
      src/qscint/src/Qsci/qscilexeryaml.h
  95. 2 2
      src/qscint/src/Qsci/qscimacro.h
  96. 2 2
      src/qscint/src/Qsci/qsciprinter.h
  97. 1 1
      src/qscint/src/Qsci/qsciscintilla.h
  98. 1 1
      src/qscint/src/Qsci/qsciscintillabase.h
  99. 2 2
      src/qscint/src/Qsci/qscistyle.h
  100. 2 2
      src/qscint/src/Qsci/qscistyledtext.h

+ 60 - 3
src/CmpareMode.cpp

@@ -983,7 +983,9 @@ CODE_ID CmpareMode::readLineFromFile(uchar* m_fileFpr, const int fileLength, con
 
 
 //扫描文件的字符编码,不输出文件
-CODE_ID CmpareMode::scanFileRealCode(QString filePath)
+//扫描多少行scanLineNum 默认100
+//如果是-1 之前全部扫描
+CODE_ID CmpareMode::scanFileRealCode(QString filePath, int scanLineNum)
 {
 	QFile file(filePath);
 	file.open(QIODevice::ReadOnly);
@@ -1051,8 +1053,10 @@ CODE_ID CmpareMode::scanFileRealCode(QString filePath)
 
 		++lineNums;
 
-		//最多扫描200行,加块速度。速度与精确性的权衡
-		if (lineNums >= 200)
+		//默认最多扫描200行,加块速度。速度与精确性的权衡
+		//对于打开文件,默认扫描前面的200行,加快速度。
+		//对于编码转换,为了精确,默认全部都要处理
+		if ((scanLineNum != -1) && (lineNums >= scanLineNum))
 		{
 			break;
 		}
@@ -1094,3 +1098,56 @@ CODE_ID CmpareMode::scanFileOutPut(CODE_ID code, QString filePath, QList<LineFil
 
 	return code;
 }
+
+//读取文件,并输出
+//bytes charsNums:文件字符个数,不是文件大小
+//20220908 自动判断是否是二进制文件。isHexFile 是输出
+//20230304 新增,一次性读取文件,不检测每行文本,加快速度。existGrbledCode 是否存在乱码
+CODE_ID CmpareMode::scanFileOutPut(QFile& pFile, CODE_ID code, QString filePath, QString& outText, bool & existGrbledCode)
+{
+	QByteArray outTextBytes = pFile.readAll();
+
+	if (outTextBytes.size() == 0)
+	{
+		outText = "";
+		existGrbledCode = false;
+		return CODE_ID::UTF8_NOBOM;
+	}
+
+	if (code == UNKOWN)
+	{
+		code = getTextFileEncodeType((uchar * )outTextBytes.data(), pFile.size(), filePath);
+
+		//编码还是检测失败,这里概率是比较小的。
+		if (code == CODE_ID::UNKOWN)
+		{
+			//无条件按照ANSI/GBK编码打开
+			code = CODE_ID::GBK;
+		}
+	}
+
+	int lineStartPos = 0; //uicode_le前面有2个特殊标识,故跳过2
+
+	if (code == CODE_ID::UNICODE_BE || code == CODE_ID::UNICODE_LE)
+	{
+		lineStartPos = 2;
+	}
+	else if (code == CODE_ID::UTF8_BOM)
+	{
+		lineStartPos = 3;
+	}
+		
+	bool codeSucess = Encode::tranStrToUNICODE(code, outTextBytes.data()+ lineStartPos, outTextBytes.size()- lineStartPos, outText);
+
+	//如果存在乱码,而且不是以gbk编码打开,再无条件尝试ASNI/GBK编码打开。如果是国际版,后续还得完善策略,得无条件以ASNI本地编码打开。
+	if (!codeSucess && (code != CODE_ID::GBK))
+	{
+		code = CODE_ID::GBK;
+		outText.clear();
+		codeSucess = Encode::tranStrToUNICODE(code, outTextBytes.data() + lineStartPos, outTextBytes.size() - lineStartPos, outText);
+	}
+	existGrbledCode = !codeSucess;
+
+	return code;
+}
+

+ 2 - 1
src/CmpareMode.h

@@ -70,8 +70,9 @@ public:
 	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 scanFileRealCode(QString filePath,int scanLineNum=200);
 	static CODE_ID scanFileOutPut(CODE_ID code, QString filePath, QList<LineFileInfo>& outputLineInfoVec, int & maxLineSize, int & charsNums, bool &isHexFile);
+	static CODE_ID scanFileOutPut(QFile& pFile, CODE_ID code, QString filePath, QString& outText, bool& existGrbledCode);
 
 	static CODE_ID getTextFileEncodeType(uchar* fileFpr, int fileLength, QString filePath="", bool isCheckHead = true);
 	static bool tranUnicodeLeToUtf8Bytes(uchar* fileFpr, const int fileLength, QString& outUtf8Bytes, bool isSkipHead=false);

BIN
src/RealCompare.rc


BIN
src/Resources/edit/global/ndd.ico


BIN
src/Resources/edit/styledark/mark.png


+ 357 - 71
src/cceditor/ccnotepad.cpp

@@ -192,7 +192,7 @@ int getFileNewIndexProperty(QWidget* pwidget)
 	return pwidget->property(Edit_File_New).toInt();
 }
 
-void setTextChangeProperty(QWidget* pwidget, bool status)
+inline void setTextChangeProperty(QWidget* pwidget, bool status)
 {
 	QVariant v(status);
 	pwidget->setProperty(Edit_Text_Change, v);
@@ -452,6 +452,8 @@ QString watchFilePath;
 
 QStringList CCNotePad::s_findHistroy;
 
+QStringList CCNotePad::s_replaceHistroy;
+
 int CCNotePad::s_autoWarp = 0; //自动换行
 int CCNotePad::s_indent = 0; //自动缩进
 int CCNotePad::s_showblank = 0; //显示空白
@@ -1501,14 +1503,7 @@ void CCNotePad::setUserDefShortcutKey(int shortcutId)
 			ui.actionGoline->setShortcut(keySeq);
 		
 		break;
-
-	case File_Compare_ID:
-		break;
-	case Dir_Compare_ID:
-		break;
-	case Bin_Compare_ID:
-		break;
-
+		
 	case Trans_code_ID:
 		keySeq = ShortcutKeyMgr::getUserDefShortcutKey(Trans_code);
 			m_transcode->setShortcut(keySeq);
@@ -1781,8 +1776,10 @@ void CCNotePad::onPlugWork(bool check)
 		if (pMainCallBack != NULL)
 		{
 			std::function<QsciScintilla* ()> foundCallBack = std::bind(&CCNotePad::getCurEditView, this);
+			std::function<bool(int, void*)> pluginCallBack = std::bind(&CCNotePad::pluginInvoke, this, std::placeholders::_1, std::placeholders::_2);
+
+			pMainCallBack(this, plugPath, foundCallBack, pluginCallBack, nullptr);
 
-			pMainCallBack(this, plugPath, foundCallBack, nullptr);
 		}
 		else
 		{
@@ -1805,8 +1802,9 @@ void CCNotePad::sendParaToPlugin(NDD_PROC_DATA& procData)
 		if (pMainCallBack != NULL)
 		{
 			std::function<QsciScintilla* ()> foundCallBack = std::bind(&CCNotePad::getCurEditView, this);
+			std::function<bool(int, void*)> pluginCallBack = std::bind(&CCNotePad::pluginInvoke, this, std::placeholders::_1, std::placeholders::_2);
 
-			pMainCallBack(this, plugPath, foundCallBack, &procData);
+			pMainCallBack(this, plugPath, foundCallBack, pluginCallBack, &procData);
 		}
 		else
 		{
@@ -2154,7 +2152,7 @@ void CCNotePad::initNotePadSqlOptions()
 	ScintillaEditView::s_noUseTab = (1 == NddSetting::getKeyValueFromNumSets(key1)) ? true : false;
 
 	ScintillaEditView::s_bigTextSize = NddSetting::getKeyValueFromNumSets(MAX_BIG_TEXT);
-	if (ScintillaEditView::s_bigTextSize < 50 || ScintillaEditView::s_bigTextSize > 300)
+	if (ScintillaEditView::s_bigTextSize < 50 || ScintillaEditView::s_bigTextSize > 600)
 	{
 		ScintillaEditView::s_bigTextSize = 100;
 }
@@ -3376,6 +3374,14 @@ void CCNotePad::slot_lexerActTrig(QAction *action)
 //保存最近打开文件到数据库。文件只有在关闭时,才写入最近列表。不关闭的下次自动恢复打开
 void CCNotePad::saveReceneOpenFile()
 {
+	int clearOpenfilelist = NddSetting::getKeyValueFromDelayNumSets(CLEAR_OPENFILE_ON_CLOSE);
+	//开启了关闭时清空打开历史列表
+	if (clearOpenfilelist == 1)
+	{
+		NddSetting::updataKeyValueFromDelaySets(RECENT_OPEN_FILE, "");
+		return;
+	}
+
 	QString rFile(RECENT_OPEN_FILE);
 
 	const int maxRecord = 15;
@@ -3538,7 +3544,8 @@ void CCNotePad::setLangsDescLable(QString &langDesc)
 //重新加载文件。这里有个问题,文件的序号会跳动,要解决跳动问题。
 //这里不能销毁当前pedit,加载编码也要保持不变。而且加载的文件一定是普通文本模式
 //目前只在文本文件被修改后,外部自动加载的场景
-void CCNotePad::reloadEditFile(ScintillaEditView* pEdit, bool isTailfOn)
+//如果isTailfOn == true, 则从startReadSize开始读取文件,不从头读取。startReadSize=-1则还是从头,否则从startReadSize开始
+void CCNotePad::reloadEditFile(ScintillaEditView* pEdit, bool isTailfOn, qint64 startReadSize)
 {
 	QString filePath = pEdit->property(Edit_View_FilePath).toString();
 
@@ -3553,16 +3560,35 @@ void CCNotePad::reloadEditFile(ScintillaEditView* pEdit, bool isTailfOn)
 
 	//下面这个clear会触发文本修改,要避免不必要的消息循环。先屏蔽一些信号
 	disEnableEditTextChangeSign(pEdit);
+	if (isTailfOn && startReadSize != -1)
+	{
+		//如果是tail模式,则不要直接把文档清空
+	}
+	else
+	{
 	pEdit->clear();
+	}
 	pEdit->setProperty(Edit_Text_Change, QVariant(false));
 	setSaveButtonStatus(false);
 
-	int errCode = FileManager::getInstance().loadFileDataInText(pEdit, filePath, code, lineEnd, nullptr, false, this);
+	int errCode = 0;
+
+	if (isTailfOn && startReadSize != -1)
+	{
+		//使用tailf读取尾部一部分数据;而不是全部读取
+		errCode = FileManager::getInstance().loadFileDataInTextFromOffset(pEdit, filePath, code, this, startReadSize);
+	}
+	else
+	{
+		errCode = FileManager::getInstance().loadFileDataInText(pEdit, filePath, code, lineEnd, nullptr, false, this);
+	}
 
 	enableEditTextChangeSign(pEdit);
 
-	if (errCode == 5)
+	if (6 == errCode)
 	{
+		//可能存在乱码,给出警告。还是以编辑模式打开
+		ui.statusBar->showMessage(tr("File %1 open success. But Exist Garbled code !"));
 	}
 	else if (errCode != 0)
 	{
@@ -3575,17 +3601,44 @@ void CCNotePad::reloadEditFile(ScintillaEditView* pEdit, bool isTailfOn)
 		lineNum = pEdit->lines();
 	}
 	pEdit->execute(SCI_GOTOLINE, lineNum - 1);
+	
 }
 
 #ifdef Q_OS_WIN
-void CCNotePad::on_roladFile(ScintillaEditView* pEdit)
+void CCNotePad::on_roladFile(ScintillaEditView* pEdit,quint64 lastSize, qint64 curSize)
 {
 	pEdit->setProperty(Modify_Outside, QVariant(true));
-	checkRoladFile(pEdit);	
+	checkRoladFile(pEdit, lastSize);
 }
 #endif
 
-bool CCNotePad::checkRoladFile(ScintillaEditView* pEdit)
+void CCNotePad::doReloadTxtFile(ScintillaEditView* pEdit, bool isOnTail, qint64 startReadSize) 
+{
+	//reloadEditFile 里面会关闭和新增tab,触发一系列的currentChanged
+	disconnect(ui.editTabWidget, &QTabWidget::currentChanged, this, &CCNotePad::slot_tabCurrentChanged);
+	reloadEditFile(pEdit, isOnTail, startReadSize);
+	pEdit->setProperty(Modify_Outside, QVariant(false));
+	connect(ui.editTabWidget, &QTabWidget::currentChanged, this, &CCNotePad::slot_tabCurrentChanged, Qt::UniqueConnection);
+};
+
+//初次进入文件tailf模式。把文件清空,而且只留100行文件
+void CCNotePad::firstTimeIntoTail(ScintillaEditView* pEdit, int remainLineNums)
+{
+	int lineCount = pEdit->lines();
+	int startLineNum = 0;
+	if (lineCount >= remainLineNums)
+	{
+		startLineNum = lineCount - remainLineNums;
+	}
+	int pos = pEdit->execute(SCI_POSITIONFROMLINE, startLineNum);
+	disEnableEditTextChangeSign(pEdit);
+	pEdit->clear();
+	enableEditTextChangeSign(pEdit);
+	doReloadTxtFile(pEdit, true, pos);
+}
+
+//startReadSize == -1 则从头开始读取。否则从startReadSize开始
+bool CCNotePad::checkRoladFile(ScintillaEditView* pEdit, qint64 startReadSize)
 {
 	if (pEdit != nullptr && pEdit->property(Modify_Outside).toBool())
 	{
@@ -3597,8 +3650,6 @@ bool CCNotePad::checkRoladFile(ScintillaEditView* pEdit)
 
 		m_isInReloadFile = true;
 
-		QString filePath = pEdit->property(Edit_View_FilePath).toString();
-
 		int tailStatus = getFileTailProperty(pEdit);
 
 		if (tailStatus != 1)
@@ -3606,25 +3657,38 @@ bool CCNotePad::checkRoladFile(ScintillaEditView* pEdit)
 			QApplication::beep();
 		}
 
-		auto doReload = [this](ScintillaEditView* pEdit, bool isOnTail) {
-			//reloadEditFile 里面会关闭和新增tab,触发一系列的currentChanged
-			disconnect(ui.editTabWidget, &QTabWidget::currentChanged, this, &CCNotePad::slot_tabCurrentChanged);
-			reloadEditFile(pEdit, isOnTail);
-			pEdit->setProperty(Modify_Outside, QVariant(false));
-			connect(ui.editTabWidget, &QTabWidget::currentChanged, this, &CCNotePad::slot_tabCurrentChanged, Qt::UniqueConnection);
-		};
-
 		//如果是开启了taif,则不提示,直接重新加载文件
 		if (tailStatus == 1)
 		{
-			doReload(pEdit,true);
+			//如果是进入tailf模式,但是startReadSize == -1.则什么也不干。
+			//等监控超时后,后续走tailf差异读取模式。
+			if (startReadSize == -1)
+			{
+				//这里什么也不做。坐等超时后,走下面的逻辑
 		}
 		else
 		{
+				//如果文件大于3000行,则删除内容,只保留当前100行,继续tailf
+				if (pEdit->lines() < 3000)
+				{
+					doReloadTxtFile(pEdit, true, startReadSize);
+				}
+				else
+				{
+					firstTimeIntoTail(pEdit,100);
+				}
+				
+			}
+
+		}
+		else 
+		{
+			QString filePath = pEdit->property(Edit_View_FilePath).toString();
+
 			int ret = QMessageBox::question(this, tr("Reload"), tr("\"%1\" This file has been modified by another program. Do you want to reload it?").arg(filePath), tr("Yes[Reload]"), tr("No[Drop]"), tr("On Tailf"));
 			if(ret == 0)
 			{
-				doReload(pEdit, false);
+				doReloadTxtFile(pEdit, false, startReadSize);
 			}
 			else if (ret == 1)
 			{
@@ -3634,8 +3698,10 @@ bool CCNotePad::checkRoladFile(ScintillaEditView* pEdit)
 			else if (ret == 2)
 			{
 				m_tailf->setChecked(true);
-				doReload(pEdit, true);
 
+				//这里也是首次开启tailf
+				//读取最后3000行的内容。进入tailf模式
+				firstTimeIntoTail(pEdit,3000);
 				//开启监控
 				tailfile(true,pEdit);
 			}
@@ -3698,7 +3764,8 @@ void CCNotePad::enableEditTextChangeSign(ScintillaEditView* pEdit)
 //直到保存后,再放开
 void CCNotePad::disEnableEditTextChangeSign(ScintillaEditView* pEdit)
 {
-	pEdit->disconnect(SIGNAL(textChanged()));
+	//pEdit->disconnect(SIGNAL(textChanged()));
+	disconnect(pEdit, &ScintillaEditView::textChanged, this, &CCNotePad::slot_editViewMofidyChange);
 }
 
 //编辑框文本变化后,设置对应的变化状态
@@ -3905,10 +3972,22 @@ void CCNotePad::tabClose(int index, bool isInQuit)
 	{
 		QApplication::beep();
 
-		int ret = QMessageBox::question(this, tr("Do you want to save changes to before closing?"), tr("If you don't save the changes you made in file %1, you'll lose them forever.").arg(filePath), tr("Yes"), tr("No"), tr("Cancel"));
-	
+		QMessageBox askSave(QMessageBox::Question, tr("Do you want to save changes to before closing?"), \
+			tr("If you don't save the changes you made in file %1, you'll lose them forever.").arg(filePath), \
+			QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, this);
+		QPushButton* okButton = (QPushButton *) askSave.button(QMessageBox::Yes);
+		okButton->setText(tr("&Yes"));
+
+		okButton = (QPushButton*)askSave.button(QMessageBox::No);
+		okButton->setText(tr("&No"));
+
+		okButton = (QPushButton*)askSave.button(QMessageBox::Cancel);
+		okButton->setText(tr("&Cancel"));
+
+		int ret = askSave.exec();
+
 		//保存
-		if (ret == 0)
+		if (ret == QMessageBox::Yes)
 		{
 			saveTabEdit(index);
 
@@ -3918,7 +3997,7 @@ void CCNotePad::tabClose(int index, bool isInQuit)
 				return;
 		}
 		}
-		else if (ret == 2)
+		else if (ret == QMessageBox::Cancel)
 		{
 			m_isQuitCancel = true;
 			return;
@@ -4008,7 +4087,12 @@ ScintillaEditView* CCNotePad::newTxtFile(QString name, int index, QString conten
 	if (!contentPath.isEmpty())
 	{
 		int ret = FileManager::getInstance().loadFileDataInText(pEdit, contentPath, code, lineEnd, nullptr, false, this);
-		if (ret != 0)
+		if (6 == ret)
+		{
+			//可能存在乱码,给出警告。还是以编辑模式打开
+			ui.statusBar->showMessage(tr("File %1 open success. But Exist Garbled code !"));
+		}
+		else if (ret != 0)
 		{
 			ui.statusBar->showMessage(tr("Restore Last Temp File %1 Failed").arg(contentPath));
 		}
@@ -4161,9 +4245,9 @@ bool CCNotePad::reloadTextFileWithCode(CODE_ID code)
 		if (docType == TXT_TYPE)
 		{
 			int errCode = FileManager::getInstance().loadFileDataInText(pEdit, filePath, code, lineEnd, this, false,this);
-		if (errCode == 5)
+			if (errCode == 6)
 		{
-			//只读模式。暂时什么也不做
+				//有乱码
 		}
 			else if (errCode != 0)
 		{
@@ -4527,11 +4611,11 @@ bool CCNotePad::openTextFile(QString filePath, bool isCheckHex, CODE_ID code)
 			//用户同意以二进制格式打开文件
 			return openHexFile(filePath);
 		}
-		else if (5 == ret)
-		{
-			isReadOnly = true;
-			//只读模式
-		}
+		//else if (5 == ret)
+		//{
+		//	isReadOnly = true;
+		//	//只读模式
+		//}
 		else if (6 == ret)
 		{
 			//可能存在乱码,给出警告。还是以编辑模式打开
@@ -5150,7 +5234,7 @@ bool CCNotePad::tryRestoreFile(QString filePath)
 bool CCNotePad::openFile(QString filePath, int lineNum)
 {
 	s_padTimes++;
-
+	//如果是相对路径
 	getRegularFilePath(filePath);
 
 	QFileInfo fi(filePath);
@@ -5223,6 +5307,11 @@ void CCNotePad::slot_slectionChanged()
 
 void CCNotePad::slot_actionOpenFile_toggle(bool /*checked*/)
 {
+	if (s_lastOpenDirPath.isEmpty())
+	{
+		s_lastOpenDirPath = NddSetting::getKeyValueFromDelaySets(LAST_OPEN_DIR);
+	}
+
 	QFileDialog fd(this,QString(), s_lastOpenDirPath);
 	fd.setFileMode(QFileDialog::ExistingFile);
 	
@@ -5240,6 +5329,7 @@ void CCNotePad::slot_actionOpenFile_toggle(bool /*checked*/)
 	}
 }
 
+#if 0
 #ifdef _WIN32
 void hide_file(const QString& szFile)
 {
@@ -5251,12 +5341,13 @@ void hide_file(const QString& szFile)
 #endif // !UNICODE
 }
 #endif // _WIN32
+#endif
 
 //bool isBakWrite:是否进行保护写,即先写swap文件,再写源文件。这样可以避免突然断电导致源文件被清空
 //isBakWrite 是否写保护swp文件,默认true。只有新文件时不需要,因为新文件不存在覆盖写的问题
 //isStatic 是否静默:不弹出对话框,在外部批量查找替换文件夹时使用,避免弹窗中断。默认false
 //isClearSwpFile:是否回收swp交换文件,在外部批量查找替换文件夹时使用,替换后直接删除swp文件。默认false
-bool  CCNotePad::saveFile(QString fileName, ScintillaEditView* pEdit, bool isBakWrite, bool isStatic,bool isClearSwpFile)
+bool  CCNotePad::saveFile(QString fileName, ScintillaEditView* pEdit, bool isBakWrite, bool isStatic,bool /*isClearSwpFile*/)
 {
 	QFile srcfile(fileName);
 	
@@ -5390,7 +5481,7 @@ bool  CCNotePad::saveFile(QString fileName, ScintillaEditView* pEdit, bool isBak
 		bool success = saveWork(swapfile, fileName, true);
 		if (success)
 		{
-#ifdef _WIN32
+#if 0 //不要这个了,windows下无条件删除
 			if (!isClearSwpFile)
 			{
 				hide_file(swapFilePath);
@@ -5402,10 +5493,18 @@ bool  CCNotePad::saveFile(QString fileName, ScintillaEditView* pEdit, bool isBak
 			return false;
 		}
 		}
+#ifdef _WIN32
+		//windows下面如果保存成功,则无条件删除swap文件,许多用户反感这个.swap文件存在
+		if (success)
+		{
+			QFile::remove(swapFilePath);
+		}
+#else
 		if (success && isClearSwpFile)
 		{
 			QFile::remove(swapFilePath);
 	}
+#endif
 		
 	}
 	return true;
@@ -6093,6 +6192,8 @@ void CCNotePad::closeFileStatic(int index, QSettings& qs)
 	removeWatchFilePath(filePath);
 	pw->deleteLater();
 }
+
+
 void CCNotePad::closeAllFileStatic()
 {
 	QString tempFileList = QString("notepad/temp/list");
@@ -6253,8 +6354,12 @@ void CCNotePad::closeEvent(QCloseEvent * event)
 	}
 	}
 
+	//保存上次打开目录
+	 if (!CCNotePad::s_lastOpenDirPath.isEmpty())
+	{
+		NddSetting::updataKeyValueFromDelaySets(LAST_OPEN_DIR, CCNotePad::s_lastOpenDirPath);
+	}
 	//保存大小
-
 	QByteArray curGeo = saveGeometry();
 	NddSetting::updataKeyByteArrayValue(WIN_POS, curGeo);
 
@@ -6626,7 +6731,11 @@ void CCNotePad::tailfile(bool isOn, ScintillaEditView* pEdit)
 						//这里不能直接更新,而是要发生信号出去。否则跨线程访问,可能发生错误或告警
 						//pEdit->setProperty(Modify_Outside, QVariant(true));
 						//checkRoladFile(pEdit);
-						emit this->tailFileChange(pEdit);
+						quint64 lastSize = 0;
+						quint64 curSize = 0;
+
+						fileChanges.getDiffFileSize(lastSize,curSize);
+						emit this->tailFileChange(pEdit, lastSize, curSize);
 					}
 					//如果退出监控。这里要注意,一定要是volidate的,否则多线程获取不到该变化
 					//使用了原子变量,效果是一样的,多个线程均可见
@@ -6783,15 +6892,21 @@ int CCNotePad::initFindWindow(FindTabIndex type)
 				QVariant history = qs.value("keys", "");
 				s_findHistroy = history.toStringList();
 			}
+			if (qs.contains("replace"))
+			{
+				QVariant replaceHistory = qs.value("replace", "");
+				s_replaceHistroy = replaceHistory.toStringList();
+		}
 		}
 
 		pFind->setFindHistory(&s_findHistroy);
-	
+		pFind->setReplaceHistory(&s_replaceHistroy);
+
 		pFind->setTabWidget(ui.editTabWidget);
 
 		if((TXT_TYPE == docType) || (BIG_TEXT_RO_TYPE == docType) || (SUPER_BIG_TEXT_RO_TYPE == docType))
 		{
-			connect(pFind, &FindWin::sign_findAllInCurDoc, this, &CCNotePad::slot_showFindAllInCurDocResult);
+			//connect(pFind, &FindWin::sign_findAllInCurDoc, this, &CCNotePad::slot_showFindAllInCurDocResult);
 			connect(pFind, &FindWin::sign_findAllInOpenDoc, this, &CCNotePad::slot_showfindAllInOpenDocResult);
 			connect(pFind, &FindWin::sign_replaceSaveFile, this, &CCNotePad::slot_saveFile);
 			connect(pFind, &FindWin::sign_clearResult, this, &CCNotePad::slot_clearFindResult);
@@ -6893,6 +7008,13 @@ void CCNotePad::slot_saveSearchHistory()
 		s_findHistroy = s_findHistroy.mid(0, 15);
 	}
 	qs.setValue("keys", s_findHistroy);
+
+	if (s_replaceHistroy.count() > 15)
+	{
+		s_replaceHistroy = s_replaceHistroy.mid(0, 15);
+	}
+	qs.setValue("replace", s_replaceHistroy);
+
 	qs.sync();
 }
 
@@ -6984,8 +7106,8 @@ void CCNotePad::clearHighlightWord(QString signWord, ScintillaEditView* pEdit)
 			delete r;
 			curMarkRecord.removeAt(i);
 	}
-	
 		}
+
 void CCNotePad::slot_clearWordHighlight()
 {
 	QWidget* pw = ui.editTabWidget->currentWidget();
@@ -7121,7 +7243,9 @@ void  CCNotePad::initFindResultDockWin()
 		m_dockSelectTreeWin->setAllowedAreas(Qt::LeftDockWidgetArea| Qt::RightDockWidgetArea |Qt::BottomDockWidgetArea);
 
 		m_pResultWin = new FindResultWin(m_dockSelectTreeWin);
-		connect(m_pResultWin, &FindResultWin::itemDoubleClicked, this, &CCNotePad::slot_findResultItemDoubleClick);
+		//connect(m_pResultWin, &FindResultWin::itemDoubleClicked, this, &CCNotePad::slot_findResultItemDoubleClick);
+		connect(m_pResultWin, &FindResultWin::lineDoubleClicked, this, &CCNotePad::on_findResultlineDoubleClick);
+		
 		connect(m_pResultWin, &FindResultWin::showMsg, this, [this](QString& msg) {
 			ui.statusBar->showMessage(msg,5000);
 		});
@@ -7235,16 +7359,62 @@ void CCNotePad::slot_findResultItemDoubleClick(const QModelIndex &index)
 
 }
 
+//双击文件leve=2的节点后,显示文件并定位到文件位置中去高亮
+void CCNotePad::on_findResultlineDoubleClick(QString* pFilePath, int pos, int end)
+{
+	auto locationCurrentEdit = [this](QString filePath)->ScintillaEditView* {
+
+		getRegularFilePath(filePath);
+
+		ScintillaEditView* pEdit = dynamic_cast<ScintillaEditView*>(ui.editTabWidget->currentWidget());
+		if (pEdit != nullptr && (filePath == getFilePathProperty(pEdit)))
+		{
+			return pEdit;
+		}
+
+		//不在则遍历插值定位到
+		for (int i = 0; i < ui.editTabWidget->count(); ++i)
+		{
+			pEdit = dynamic_cast<ScintillaEditView*>(ui.editTabWidget->widget(i));
+			if (pEdit != nullptr && (filePath == getFilePathProperty(pEdit)))
+			{
+				ui.editTabWidget->setCurrentIndex(i);
+				return pEdit;
+			}
+		}
+
+		//走到这里,说明文档已经关闭,不在当前打开框中
+		//还是没有找到,则新建打开文件
+		if (openFile(filePath))
+		{
+			ScintillaEditView* pEdit = dynamic_cast<ScintillaEditView*>(ui.editTabWidget->currentWidget());
+			return pEdit;
+		}
+
+		ui.statusBar->showMessage(tr("file %1 was not exists !").arg(filePath), 5000);
+		QApplication::beep();
+		return nullptr;
+	};
+
+	ScintillaEditView* pCurEdit = locationCurrentEdit(*pFilePath);
+	if (pCurEdit != nullptr)
+	{
+		pCurEdit->execute(SCI_SETSEL, pos, end);
+	}	
+}
+
+#if 0
 void CCNotePad::slot_showFindAllInCurDocResult(FindRecords* record)
 {
 	initFindResultDockWin();
 
 	m_dockSelectTreeWin->setWindowTitle(tr("Find result - %1 hit").arg(record->records.size()));
 
-	m_pResultWin->appendResultsToShow(record);
+	//m_pResultWin->appendResultsToShow(record);
 
 	m_dockSelectTreeWin->show();
 }
+#endif
 
 void CCNotePad::slot_showfindAllInOpenDocResult(QVector<FindRecords*>* record, int hits, QString whatFind)
 {
@@ -7512,11 +7682,11 @@ void CCNotePad::transDocToEncord(CODE_ID destCode)
 		//等到文件保存时才执行
 		if (srcCode != newCode)
 		{
-			QVariant editTextCode((int)newCode);
-			pEdit->setProperty(Edit_Text_Code, editTextCode);
+			setCodeTypeProperty(pEdit, (int)newCode);
 
-			QVariant textChanged(true);
-			pEdit->setProperty(Edit_Text_Change, textChanged);
+			setTextChangeProperty(pEdit, true);
+
+			ui.editTabWidget->setTabIcon(ui.editTabWidget->currentIndex(), QIcon(TabNeedSave));
 
 			setSaveButtonStatus(true);
 			setSaveAllButtonStatus(true);
@@ -7911,15 +8081,15 @@ void CCNotePad::slot_aboutNdd()
 	QString title = tr("Notepad-- Version %1").arg(VersionStr);
 	pWin->setWindowTitle(title);
 	pWin->appendText(title);
-//	int status = NddSetting::getKeyValueFromNumSets(SOFT_STATUS);
-//	if (1 == status)
-//	{
-//		pWin->appendText(tr("Registered Version"));
-//	}
-//	else
-//	{
-//		pWin->appendText(tr("Free Trial"));
-//	}
+	int status = NddSetting::getKeyValueFromNumSets(SOFT_STATUS);
+	if (1 == status)
+	{
+		pWin->appendText(tr("Registered Version"));
+	}
+	else
+	{
+		pWin->appendText(tr("Free Trial"));
+	}
 	pWin->show();
 	registerEscKeyShort(pWin);
 #ifdef uos
@@ -7990,6 +8160,11 @@ void CCNotePad::dropEvent(QDropEvent* e)
 	e->accept();
 }
 
+void CCNotePad::dragLeaveEvent(QDragLeaveEvent* event)
+{
+	qDebug() << "drag level";
+}
+
 //目前只有一个Tabwidget的双击事件。
 bool CCNotePad::eventFilter(QObject * watched, QEvent * event)
 {
@@ -8481,7 +8656,7 @@ bool CCNotePad::restoreDirtyExistFile(QString& filePath, QString& tempFilePath)
 	if (!tempFilePath.isEmpty())
 	{
 		int ret = FileManager::getInstance().loadFileDataInText(pEdit, tempFilePath, code, lineEnd, nullptr, false,this);
-		if (ret != 0)
+		if ((ret != 6) && (ret != 0))
 		{
 			isLoadOrgin = true;
 			ui.statusBar->showMessage(tr("Restore Last Temp File %1 Failed").arg(tempFilePath), 5000);
@@ -8511,10 +8686,14 @@ bool CCNotePad::restoreDirtyExistFile(QString& filePath, QString& tempFilePath)
 			//用户同意以二进制格式打开文件
 			return openHexFile(filePath);
 		}
-		else if (5 == ret)
+		//else if (5 == ret)
+		//{
+		//	isReadOnly = true;
+		//	//只读模式
+		//}
+		else if (6 == ret)
 		{
-			isReadOnly = true;
-			//只读模式
+			//存在乱码,还是打开
 		}
 		else if (0 != ret)
 		{
@@ -9606,6 +9785,46 @@ void CCNotePad::on_quitActiveWindow()
 	}
 }
 
+#if 0 
+//修改主题颜色//暂时不开始,发现MAC下有不开启深色的配置
+void CCNotePad::changeAppFontColor(QColor color)
+{
+	//把存在的界面都关闭。发现如果不关闭,颜色不会更新
+
+	if (!m_pFindWin.isNull())
+	{
+		QByteArray curGeo = m_pFindWin->saveGeometry();
+		NddSetting::updataKeyByteArrayValue(FINDWINSIZE, curGeo);
+
+		m_pFindWin.data()->deleteLater();
+	}
+
+	if (!m_pHexGotoWin.isNull())
+	{
+		m_pHexGotoWin.data()->close();
+	}
+
+	if (!m_columnEditWin.isNull())
+	{
+		m_columnEditWin.data()->close();
+	}
+
+
+	//filelistwin还存在
+	if (!m_dockFileListWin.isNull())
+	{
+		NddSetting::updataKeyValueFromNumSets(FILELISTSHOW, 1);
+		m_dockFileListWin.data()->close();
+	}
+
+	if (m_dockSelectTreeWin != nullptr)
+	{
+		m_dockSelectTreeWin->deleteLater();
+		m_dockSelectTreeWin = nullptr;
+	}
+}
+#endif
+
 void CCNotePad::on_md5hash()
 {
 	Md5hash* pWin = new Md5hash(this);
@@ -9613,3 +9832,70 @@ void CCNotePad::on_md5hash()
 	pWin->setAttribute(Qt::WA_DeleteOnClose);
 	pWin->show();
 }
+
+
+#ifdef NO_PLUGIN
+//插件中调用主程序的功能。
+//cmdId 执行什么动作,一定固定后,主程序不能随便修改,否则会引发兼容性问题。
+bool CCNotePad::pluginInvoke(int cmdId, void* data)
+{
+	bool ret = false;
+	switch (cmdId)
+	{
+	case 1:
+	{
+		//新建一个文件。
+		slot_actionNewFile_toggle(true);
+
+		//默认不需要。
+		if (data != nullptr)
+		{
+			QVariant* pVar = (QVariant*)data;
+			//回传回去新建文件的名称
+			ScintillaEditView* pw = getCurEditView();
+			if (pw != nullptr)
+			{
+				pVar->setValue(getFilePathProperty(pw));
+			}
+
+		}
+		ret = true;
+	}
+	break;
+	case 2:
+	{
+		//设定当前编辑器的语言。0 js 1 json
+		int lang = *((int*)data);
+
+		LangType langs = ((lang == 0) ? L_JAVASCRIPT : L_JSON);
+
+		ScintillaEditView* pEdit = getCurEditView();
+		if (pEdit != nullptr)
+		{
+			QsciLexer* curLexer = pEdit->lexer();
+			if (curLexer == nullptr)
+			{
+				//设定为目标语法
+				QsciLexer* lexer = ScintillaEditView::createLexer(langs);
+				pEdit->setLexer(lexer);
+			}
+			else if (curLexer->lexerId() != langs)
+			{
+				pEdit->setLexer(nullptr);
+				delete curLexer;
+				curLexer = nullptr;
+
+				QsciLexer* lexer = ScintillaEditView::createLexer(langs);
+				pEdit->setLexer(lexer);
+			}
+			syncCurDocLexerToMenu(pEdit);
+		}
+		ret = true;
+	}
+
+	default:
+		break;
+	}
+	return ret;
+}
+#endif

+ 22 - 5
src/cceditor/ccnotepad.h

@@ -23,6 +23,7 @@
 #include "findwin.h"
 #include "pluginGl.h"
 
+
 //class ScintillaEditView;
 class ScintillaHexEditView;
 class FindRecords;
@@ -33,7 +34,6 @@ class CompareWin;
 struct HexFileMgr;
 struct TextFileMgr;
 struct BigTextEditFileMgr;
-class QtLangSet;
 
 static const char* Tail_Thread = "tailthread";
 
@@ -87,6 +87,7 @@ enum NddDocType {
 //打开模式。1 文本 2 二进制 3 大文本只读 4 文本只读
 //const char* Open_Attr = "openid";
 class FileListView;
+class QtLangSet;
 
 class CCNotePad : public QMainWindow
 {
@@ -154,7 +155,7 @@ signals:
 	void signRegisterReplay(int code);
 	void signLinkNetServer();
 #ifdef Q_OS_WIN
-	void tailFileChange(ScintillaEditView*);
+	void tailFileChange(ScintillaEditView*,qint64 lastSize, qint64 curSize);
 #endif 
 public slots:
 	void slot_changeChinese();
@@ -197,6 +198,7 @@ protected:
 	void closeEvent(QCloseEvent *event) override;
 	void dragEnterEvent(QDragEnterEvent* event) override;
 	void dropEvent(QDropEvent* e) override;
+	void dragLeaveEvent(QDragLeaveEvent* event);
 	bool eventFilter(QObject *watched, QEvent *event)override;
 #ifdef Q_OS_WIN
 	bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
@@ -235,7 +237,9 @@ private slots:
 	
 	void slot_findResultPosChangeed(Qt::DockWidgetArea area);
 	void slot_findResultItemDoubleClick(const QModelIndex & index);
+#if 0
 	void slot_showFindAllInCurDocResult(FindRecords * record);
+#endif
 	void slot_showfindAllInOpenDocResult(QVector<FindRecords*>* record, int hits, QString whatFind);
 	void slot_clearFindResult();
 	void slot_convertWinLineEnd(bool);
@@ -347,6 +351,8 @@ private slots:
 #ifdef NO_PLUGIN
 	void onPlugWork(bool check);
 	void sendParaToPlugin(NDD_PROC_DATA& procData);
+	//cmdId 执行什么动作,一定固定后,主程序不能随便修改,否则会引发兼容性问题。
+	bool pluginInvoke(int cmdId, void* data);
 #endif
 	void slot_showWebAddr(bool check);
 	void slot_langFileSuffix();
@@ -354,7 +360,7 @@ private slots:
 	void on_lineEndChange(int index);
 	void on_tailfile(bool isOn);
 #ifdef Q_OS_WIN
-	void on_roladFile(ScintillaEditView* pEdit);
+	void on_roladFile(ScintillaEditView* pEdit,quint64 lastSize, qint64 curSize);
 #endif
 	void on_md5hash();
 
@@ -396,11 +402,15 @@ private:
 	void addWatchFilePath(QString filePath);
 	void removeWatchFilePath(QString filePath);
 
-	bool checkRoladFile(ScintillaEditView * pEdit);
-	void reloadEditFile(ScintillaEditView * pEidt, bool isTailfOn = false);
+	void doReloadTxtFile(ScintillaEditView* pEdit, bool isOnTail, qint64 startReadSize);
+	void firstTimeIntoTail(ScintillaEditView* pEdit, int remainLineNums=100);
+	bool checkRoladFile(ScintillaEditView * pEdit, qint64 startReadSize=-1);
+	void reloadEditFile(ScintillaEditView * pEidt, bool isTailfOn = false, qint64 startReadSize=-1);
 	int initFindWindow(FindTabIndex type= FIND_TAB);
 
 	void setToFileRightMenu();
+	void initReceneCmp();
+	void saveReceneCmp();
 
 	QString getShortName(const QString& name);
 
@@ -471,6 +481,7 @@ private:
 	void doFold(int type, bool mode);
 	void doComment(int type);
 	void tailfile(bool isOn, ScintillaEditView* pEdit);
+	void on_findResultlineDoubleClick(QString* pFilePath, int pos, int end);
 private:
 	Ui::CCNotePad ui;
 
@@ -521,6 +532,10 @@ private:
 
 	QSharedMemory* m_shareMem;
 
+	
+
+	QList<CompareDirs*> m_cmpDirMgr;
+	QList<CompareWin*> m_cmpFileMgr;
 
 	//最近打开的对比文件和目录列表。做一个环形区
 //保存在数据库中
@@ -551,6 +566,7 @@ private:
 	QPointer<QWidget> m_pHexGotoWin;
 
 	static QStringList s_findHistroy;
+	static QStringList s_replaceHistroy;
 	static int s_padTimes;
 
 	int m_curSoftLangs; //当前语言0:自动 1 中文 2 英语
@@ -615,6 +631,7 @@ private:
 	QList<NDD_PROC_DATA> m_pluginList;
 
 public:
+	
 		static QString s_lastOpenDirPath;
 	static int s_restoreLastFile; //自动恢复上次打开的文件
 	static int s_curStyleId;

+ 3 - 0
src/cceditor/ccnotepad.ui

@@ -1627,6 +1627,9 @@
    <property name="text">
     <string>Column Block Editing</string>
    </property>
+   <property name="shortcut">
+    <string>Alt+X</string>
+   </property>
   </action>
   <action name="actionWrap">
    <property name="checkable">

+ 263 - 101
src/cceditor/filemanager.cpp

@@ -9,7 +9,9 @@
 #include <QFile>
 #include <QtGlobal>
 #include <qscilexer.h>
+#include <QFileInfo>
 
+LangType detectLanguage(QString& headContent, QString& filepath);
 
 FileManager::FileManager():m_lastErrorCode(NONE_ERROR)
 {
@@ -218,6 +220,68 @@ void FileManager::delNewFileNode(int fileIndex)
 	}
 }
 
+//和loadFileDataInText类似,但是不是从头开始读取文件,而是从startReadSize开始
+//不检查编码,直接按照fileTextCode进行读取
+int FileManager::loadFileDataInTextFromOffset(ScintillaEditView* editView, QString filePath, CODE_ID fileTextCode, QWidget* msgBoxParent, quint64 startReadSize)
+{
+	QFile file(filePath);
+
+	//如果文件不存在,直接返回
+	if (!file.exists())
+	{
+		return -1;
+	}
+
+	QFlags<QFileDevice::Permission> power = QFile::permissions(filePath);
+
+	//直接以只读的方式打开,至于能不能保存,是保存时需要考虑的问题。
+	//只需要在保存的时候获取admin权限即可
+	QIODevice::OpenMode mode;
+
+	mode = QIODevice::ExistingOnly | QIODevice::ReadOnly;
+
+	if (!file.open(mode))
+	{
+		QMessageBox::warning(msgBoxParent, tr("Error"), tr("Open File %1 failed").arg(filePath));
+		return 2;
+	}
+
+	quint64 fileSize = file.size();
+
+	//如果文件是空的。检查一下,有可能在临时文件损坏情况下出现,外面需要使用
+	if (fileSize == 0)
+	{
+		file.close();
+		return 0;
+	}
+
+	//如果读取的内容,超过了当前文件大小,则直接返回。这里是返回0,视作成功,没有新内容要读
+	if (startReadSize >= fileSize)
+	{
+		file.close();
+		return 0;
+	}
+
+	QByteArray bytes;
+
+	if (file.seek(startReadSize))
+	{
+		//读取后面所有的内容
+		bytes = file.readAll();
+	}
+
+	file.close();
+
+	QString text;
+
+	Encode::tranStrToUNICODE(fileTextCode, bytes.data(), bytes.count(), text);
+	
+	editView->append(text);
+
+	return 0;
+}
+
+#if 0
 
 //这里是以文本方式加载文件。但是可能遇到的是二进制文件,里面会做判断
 //二进制时hexAsk是否询问,当用户指定打开格式时,不需要询问
@@ -406,22 +470,182 @@ int FileManager::loadFileDataInText(ScintillaEditView* editView, QString filePat
 	return 0;
 }
 
-//加载文件,只为查找使用
-int FileManager::loadFileForSearch(ScintillaEditView* editView, QString filePath)
+#endif
+
+//20230304新增加:不再一行一行读取文件,而是一次性读取到内存,加快文本文件打开时的处理速度
+//这里是以文本方式加载文件。但是可能遇到的是二进制文件,里面会做判断
+//二进制时hexAsk是否询问,当用户指定打开格式时,不需要询问
+//MsgBoxParent::尽量把这个给一下,让MsgBox有图标,不那么难看。
+int FileManager::loadFileDataInText(ScintillaEditView* editView, QString filePath, CODE_ID& fileTextCode, RC_LINE_FORM& lineEnd, CCNotePad* callbackObj, bool hexAsk, QWidget* msgBoxParent)
 {
 	QFile file(filePath);
 
+	//如果文件不存在,直接返回
+	if (!file.exists())
+	{
+		return -1;
+	}
+
 	QFlags<QFileDevice::Permission> power = QFile::permissions(filePath);
 
-	if (!power.testFlag(QFile::ReadOwner))
+	//直接以只读的方式打开,至于能不能保存,是保存时需要考虑的问题。
+	//只需要在保存的时候获取admin权限即可
+	QIODevice::OpenMode mode;
+
+	mode = QIODevice::ExistingOnly | QIODevice::ReadOnly;
+
+	if (!file.open(mode))
 	{
-		//文件不能读
+		qDebug() << file.error();
+#ifdef Q_OS_WIN
+		//打开失败,这里一般是权限问题导致。如果是windows,在外面申请权限后继续处理
+		if (QFileDevice::OpenError == file.error())
+		{
+			if (callbackObj != nullptr)
+			{
+				return callbackObj->runAsAdmin(filePath);
+			}
 		return 1;
 	}
+#endif
+#ifdef Q_OS_UNIX
+		QMessageBox::warning(msgBoxParent, tr("Error"), tr("Open File %1 failed").arg(filePath));
+#endif
+		return 2;
+	}
+
+	qint64 fileSize = file.size();
+
+	//如果文件是空的。检查一下,有可能在临时文件损坏情况下出现,外面需要使用
+	if (fileSize == 0)
+	{
+		m_lastErrorCode = ERROR_TYPE::OPEN_EMPTY_FILE;
+		file.close();
+		return 0;
+	}
+
+	qint64 bufferSizeRequested = fileSize + qMin((qint64)(1 << 20), (qint64)(fileSize / 6));
+
+	if (bufferSizeRequested > INT_MAX)
+	{
+		QMessageBox::warning(msgBoxParent, tr("Error"), tr("File is too big to be opened by Notepad--"));
+		file.close();
+		return 3;
+	}
+
+	QString fileText;
+	bool isErrorCode = false;
+
+	fileTextCode = CmpareMode::scanFileOutPut(file, fileTextCode, filePath, fileText, isErrorCode);
+
+	//如果文件是空的。检查一下,有可能在临时文件损坏情况下出现,外面需要使用
+	if (fileText.size() == 0)
+	{
+		m_lastErrorCode = ERROR_TYPE::OPEN_EMPTY_FILE;
+		file.close();
+		return 0;
+	}
+
+	if (isErrorCode && hexAsk)
+	{
+		//检测到文件很可能是二进制文件,询问用户,是否以二进制加载
+		int ret = QMessageBox::question(msgBoxParent, tr("Open with Text or Hex? [Exist Garbled Code]"), tr("The file %1 is likely to be binary. Do you want to open it in binary?").arg(filePath), tr("Hex Open"), tr("Text Open"), tr("Cancel"));
+
+		if (ret == 0)
+		{
+			//16进制打开
+			file.close();
+			return 4;
+		}
+		else if (ret == 1)
+		{
+			//继续以文本打开
+		}
+		else
+		{
+			//取消,不打开
+			file.close();
+			return 2;
+		}
+	}
+
+	//以第一行的换行为文本的换行符。暂时只考虑win unix 。mac \r 已经淘汰,暂时不管
+	lineEnd = RC_LINE_FORM::UNKNOWN_LINE;
+
+	int pos = fileText.indexOf("\n");
+	if (pos >=1)
+	{
+		if (fileText[pos - 1] == QChar('\r'))
+		{
+			lineEnd = RC_LINE_FORM::DOS_LINE;
+		}
+		else
+		{
+			lineEnd = RC_LINE_FORM::UNIX_LINE;
+		}
+	}
+
+	if (lineEnd == UNKNOWN_LINE)
+	{
+#ifdef _WIN32
+		lineEnd = DOS_LINE;
+#else
+		lineEnd = UNIX_LINE;
+#endif
+	}
+
+	file.close();
+
+
+	//优先根据文件后缀来确定其语法风格
+	LexerInfo lxdata = CCNotePad::getLangLexerIdByFileExt(filePath);
+
+	if (lxdata.lexerId != L_TXT)
+	{
+		QsciLexer* lexer = editView->createLexer(lxdata.lexerId, lxdata.tagName);
+		editView->setLexer(lexer);
+	}
+	else
+	{
+		//利用前面100个字符,进行一个编程语言的判断
+		QString headContens = fileText.mid(0, 100);
+
+		LangType _language = detectLanguage(headContens, filePath);
+
+		if (_language >= 0 && _language < L_EXTERNAL)
+		{
+			QsciLexer* lexer = editView->createLexer(_language);
+			editView->setLexer(lexer);
+		}
+	}
+
+	//如果检测到时16进制文件,但是强行以二进制打开,则有限走setUtf8Text。
+	if (!isErrorCode)
+	{
+		editView->setText(fileText);
+	}
+	else
+	{
+		//20230203有github用户反馈,说存在乱码的文件被截断,所以后续还是不走截断
+		editView->setText(fileText);
+
+		return 6;
+	}
+
+	return 0;
+}
+
+
+//加载文件,只为查找使用
+int FileManager::loadFileForSearch(ScintillaEditView* editView, QString filePath)
+{
+	QFile file(filePath);
+
+	QFlags<QFileDevice::Permission> power = QFile::permissions(filePath);
 
 	QIODevice::OpenMode mode;
 
-	if (!power.testFlag(QFile::WriteOwner))
+	if (!power.testFlag(QFile::WriteUser))
 	{
 		//文件不能写
 		mode = QIODevice::ExistingOnly | QIODevice::ReadOnly;
@@ -433,7 +657,7 @@ int FileManager::loadFileForSearch(ScintillaEditView* editView, QString filePath
 
 	if (!file.open(mode))
 	{
-		qDebug() << file.error();
+		//qDebug() << file.error();
 		return 2;
 	}
 
@@ -441,49 +665,30 @@ int FileManager::loadFileForSearch(ScintillaEditView* editView, QString filePath
 
 	qint64 bufferSizeRequested = fileSize + qMin((qint64)(1 << 20), (qint64)(fileSize / 6));
 
-	// As a 32bit application, we cannot allocate 2 buffer of more than INT_MAX size (it takes the whole address space)
 	if (bufferSizeRequested > INT_MAX)
 	{
 		file.close();
 		return 3;
 	}
 
-	QList<LineFileInfo> outputLineInfoVec;
-
-	int maxLineSize = 0;
-	int charsNums = 0;
-	bool isHexFile = false;
-
+	bool existGrbledCode = false;
+	QString outText;
 	CODE_ID fileTextCode = CODE_ID::UNKOWN;
 
-	fileTextCode = CmpareMode::scanFileOutPut(fileTextCode, filePath, outputLineInfoVec, maxLineSize, charsNums, isHexFile);
+	fileTextCode = CmpareMode::scanFileOutPut(file, fileTextCode, filePath, outText, existGrbledCode);
 
 	//20230218 这里必须指明一下编码,否则后续会导致编码被修改
 	editView->setProperty(Edit_Text_Code, fileTextCode);
 
-	if (isHexFile)
+	if (existGrbledCode)
 	{
-		qDebug() << filePath;
+		//qDebug() << filePath;
 		file.close();
 		return 4;
 	}
-
-	if (maxLineSize > 0)
-	{
-		editView->execute(SCI_SETSCROLLWIDTH, maxLineSize * 10);
-	}
-
-	QString text;
-	text.reserve(charsNums + 1);
-
-	for (QList<LineFileInfo>::iterator it = outputLineInfoVec.begin(); it != outputLineInfoVec.end(); ++it)
-	{
-		text.append(it->unicodeStr);
-	}
-
 	file.close();
 
-	editView->setText(text);
+	editView->setText(outText);
 
 	return 0;
 }
@@ -1223,95 +1428,52 @@ void FileManager::closeBigTextRoFileHand(QString filepath)
 	}
 }
 
-//检查文件的编程语言
-LangType FileManager::detectLanguageFromTextBegining(const unsigned char *data, size_t dataLen)
+//初步检查文件的编程语言。两个标准: 1 文件头部标签 2 文件特定名称
+LangType detectLanguage(QString& headContent, QString& filepath)
 {
 	struct FirstLineLanguages
 	{
-		std::string pattern;
+		QString pattern;
 		LangType lang;
 	};
 
-	// Is the buffer at least the size of a BOM?
-	if (dataLen <= 3)
-		return L_TXT;
-
-	// Eliminate BOM if present
-	size_t i = 0;
-	if ((data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF) || // UTF8 BOM
-		(data[0] == 0xFE && data[1] == 0xFF && data[2] == 0x00) || // UTF16 BE BOM
-		(data[0] == 0xFF && data[1] == 0xFE && data[2] == 0x00))   // UTF16 LE BOM
-		i += 3;
-
-	// Skip any space-like char
-	for (; i < dataLen; ++i)
-	{
-		if (data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r')
-			break;
-	}
-
-	// Create the buffer to need to test
-	const size_t longestLength = 40; // shebangs can be large
-	std::string buf2Test = std::string((const char *)data + i, longestLength);
-
-	// Is there a \r or \n in the buffer? If so, truncate it
-	auto cr = buf2Test.find("\r");
-	auto nl = buf2Test.find("\n");
-	auto crnl = qMin(cr, nl);
-	if (crnl != std::string::npos && crnl < longestLength)
-		buf2Test = std::string((const char *)data + i, crnl);
-
-	// First test for a Unix-like Shebang
-	// See https://en.wikipedia.org/wiki/Shebang_%28Unix%29 for more details about Shebang
-	std::string shebang = "#!";
-
-	size_t foundPos = buf2Test.find(shebang);
-	if (foundPos == 0)
-	{
-		// Make a list of the most commonly used languages
-        const size_t NB_SHEBANG_LANGUAGES = 7;
-		FirstLineLanguages ShebangLangs[NB_SHEBANG_LANGUAGES] = {
-			{ "sh",		L_BASH },
-			{ "python", L_PYTHON },
-			{ "perl",	L_PERL },
-			{ "php",	L_PHP },
-			{ "ruby",	L_RUBY },
-            { "node",	L_JAVASCRIPT },
-            { "Makefile",	L_MAKEFILE}
-		};
-
-		// Go through the list of languages
-		for (i = 0; i < NB_SHEBANG_LANGUAGES; ++i)
-		{
-			if (buf2Test.find(ShebangLangs[i].pattern) != std::string::npos)
-			{
-				return ShebangLangs[i].lang;
-			}
-		}
-
-		// Unrecognized shebang (there is always room for improvement ;-)
-		return L_TXT;
-	}
-
-	// Are there any other patterns we know off?
-	const size_t NB_FIRST_LINE_LANGUAGES = 5;
-	FirstLineLanguages languages[NB_FIRST_LINE_LANGUAGES] = {
+	const size_t FIRST_LINE_LANGUAGES = 5;
+	FirstLineLanguages languages[FIRST_LINE_LANGUAGES] = {
 		{ "<?xml",			L_XML },
 		{ "<?php",			L_PHP },
 		{ "<html",			L_HTML },
 		{ "<!DOCTYPE html",	L_HTML },
-		{ "<?",				L_PHP } // MUST be after "<?php" and "<?xml" to get the result as accurate as possible
+		{ "<?",				L_PHP }
 	};
 
-	for (i = 0; i < NB_FIRST_LINE_LANGUAGES; ++i)
+	int foundPos = -1;
+	for (int i = 0; i < FIRST_LINE_LANGUAGES; ++i)
 	{
-		foundPos = buf2Test.find(languages[i].pattern);
+		foundPos = headContent.indexOf(languages[i].pattern);
 		if (foundPos == 0)
 		{
 			return languages[i].lang;
 		}
 	}
 
+	const size_t NAME_CHECK_LANGUAGES = 3;
+	FirstLineLanguages NAME_LEXER[NAME_CHECK_LANGUAGES] = {
+		{ "make",			L_MAKEFILE },
+		{ "makefile",		L_MAKEFILE },
+		{ "CMakeLists",		L_MAKEFILE },
+	};
+
+	QFileInfo fi(filepath);
+	QString baseName = fi.baseName();
+
+	for (int i = 0; i < NAME_CHECK_LANGUAGES; ++i)
+	{
+		if (0 == NAME_LEXER[i].pattern.compare(baseName, Qt::CaseInsensitive))
+		{
+			return NAME_LEXER[i].lang;
+		}
+	}
+
 	// Unrecognized first line, we assume it is a text file for now
 	return L_UNKNOWN;
 }

+ 6 - 3
src/cceditor/filemanager.h

@@ -154,8 +154,13 @@ public:
 
 	void delNewFileNode(int fileIndex);
 
-	int loadFileDataInText(ScintillaEditView * editView, QString filePath, CODE_ID & fileTextCode, RC_LINE_FORM &lineEnd, CCNotePad * callbackObj=nullptr, bool hexAsk = true, QWidget* MsgBoxParent=nullptr);
+	int loadFileDataInTextFromOffset(ScintillaEditView* editView, QString filePath, CODE_ID fileTextCode, QWidget* msgBoxParent, quint64 startReadSize);
 
+	//下面这个是旧函数,之前对比时候用的。
+	//int loadFileDataInText(ScintillaEditView * editView, QString filePath, CODE_ID & fileTextCode, RC_LINE_FORM &lineEnd, CCNotePad * callbackObj=nullptr, bool hexAsk = true, QWidget* MsgBoxParent=nullptr);
+
+	int loadFileDataInText(ScintillaEditView* editView, QString filePath, CODE_ID& fileTextCode, RC_LINE_FORM& lineEnd, CCNotePad* callbackObj = nullptr, bool hexAsk = true, QWidget* msgBoxParent = nullptr);
+	
 	int loadFileForSearch(ScintillaEditView * editView, QString filePath);
 
 	//int loadFileData(ScintillaEditView * editView, QString filePath, CODE_ID & fileTextCode, RC_LINE_FORM & lineEnd);
@@ -188,8 +193,6 @@ public:
 
 	void closeBigTextRoFileHand(QString filepath);
 
-	LangType detectLanguageFromTextBegining(const unsigned char * data, size_t dataLen);
-
 	static FileManager& getInstance() {
 		static FileManager instance;
 		return instance;

+ 1 - 1
src/columnedit.ui

@@ -153,7 +153,7 @@
            </size>
           </property>
           <property name="minimum">
-           <number>1</number>
+           <number>-100</number>
           </property>
          </widget>
         </item>

+ 10 - 1
src/ctipwin.cpp

@@ -35,8 +35,9 @@ void CTipWin::slot_delayClose()
 }
 
 
-void CTipWin::showTips(QWidget* parent, QString text, int sec)
+void CTipWin::showTips(QWidget* parent, QString text, int sec, bool isMousePos)
 {
+
 	if (parent != nullptr)
 	{
 		CTipWin* pWin = new CTipWin();
@@ -44,10 +45,18 @@ void CTipWin::showTips(QWidget* parent, QString text, int sec)
 		pWin->setAttribute(Qt::WA_DeleteOnClose);
 		pWin->showMsg(sec);
 
+		if (!isMousePos)
+		{
 		QPoint pos = parent->pos();
 		QSize size = parent->size();
 
 		QPoint newPos(pos.x() + 10, pos.y() + size.height() - 20);
 		pWin->move(newPos);
+	}
+		else
+		{
+			pWin->move(parent->cursor().pos());
+}
+
 	}
 }

+ 1 - 1
src/ctipwin.h

@@ -12,7 +12,7 @@ public:
 	~CTipWin();
 	void setTipText(QString text);
 	void showMsg(int sec = 2000);
-	static void showTips(QWidget* parent, QString text, int sec);
+	static void showTips(QWidget* parent, QString text, int sec, bool isMousePos = false);
 
 private slots:
 	void slot_delayClose();

+ 26 - 2
src/dectfilechanges.cpp

@@ -2,7 +2,7 @@
 
 #ifdef WIN32
 
-DectFileChanges::DectFileChanges()
+DectFileChanges::DectFileChanges():m_lastFileSize(0), m_curFileSize(0)
 {
 	_szFile = NULL;
 	_dwNotifyFilter = 0;
@@ -28,7 +28,16 @@ BOOL DectFileChanges::DetectChanges() {
 		rValue = TRUE;
 	}
 
+	if (rValue)
+	{
+		m_lastFileSize = getFileSize(_lastFileInfo);
+	}
 	_lastFileInfo = fInfo;
+
+	if (rValue)
+	{
+		m_curFileSize = getFileSize(_lastFileInfo);
+	}
 	return rValue;
 }
 
@@ -45,4 +54,19 @@ void DectFileChanges::Terminate()
 	_szFile = NULL;
 	_dwNotifyFilter = 0;
 }
-#endif
+quint64 DectFileChanges::getFileSize(WIN32_FILE_ATTRIBUTE_DATA& data)
+{
+	quint64 fileSize = data.nFileSizeHigh;
+	fileSize = (fileSize << 32);
+	fileSize += data.nFileSizeLow;
+
+	return fileSize;
+}
+
+void DectFileChanges::getDiffFileSize(quint64& lastSize, quint64& curSize)
+{
+	lastSize = m_lastFileSize;
+	curSize = m_curFileSize;
+}
+
+#endif

+ 9 - 0
src/dectfilechanges.h

@@ -12,6 +12,7 @@
 #define NOMINMAX
 
 #include <windows.h>
+#include <QtGlobal> 
 
 class DectFileChanges
 {
@@ -22,11 +23,19 @@ public:
 	BOOL DetectChanges();
 	void Terminate();
 
+	void getDiffFileSize(quint64& lastSize, quint64& curSize);
+
+private:
+	quint64 getFileSize(WIN32_FILE_ATTRIBUTE_DATA& data);
+
 private:
 	LPCTSTR _szFile = nullptr;
 	DWORD _dwNotifyFilter = 0;
 	WIN32_FILE_ATTRIBUTE_DATA _lastFileInfo = {};
 
+	quint64 m_lastFileSize;
+	quint64 m_curFileSize;
+
 };
 
 #endif

+ 4 - 2
src/encodeconvert.cpp

@@ -289,7 +289,7 @@ QFuture<EncodeThreadParameter*> EncodeConvert::commitTask(std::function<EncodeTh
 }
 
 
-//对比左右文件的大小,sha1值来判断文件是否相等
+//识别文件编码
 QFuture<EncodeThreadParameter_*> EncodeConvert::checkFileCode(QString filePath, QTreeWidgetItem* item)
 {
 	EncodeThreadParameter_* p = new EncodeThreadParameter_(filePath);
@@ -298,7 +298,8 @@ QFuture<EncodeThreadParameter_*> EncodeConvert::checkFileCode(QString filePath,
 	//int 0相等 1 不等
 	return commitTask([](EncodeThreadParameter_* parameter)->EncodeThreadParameter_*
 		{
-			parameter->code = CmpareMode::scanFileRealCode(parameter->filepath);
+			//整个文件都要扫描完毕。还是怕太慢,最多1000行吧
+			parameter->code = CmpareMode::scanFileRealCode(parameter->filepath,1000);
 			return parameter;
 		}
 	, p);
@@ -473,6 +474,7 @@ void EncodeConvert::scanFileCode()
 		{
 			iter->selfItem->setText(2, QString("--"));
 		}
+		//20230304 编码转换这里,不能仅仅只识别已知后缀文件,要失败所有文件
 		else if ((iter->type == RC_FILE) && DocTypeListView::isSupportExt(fileSuffix(iter->relativePath)))
 		{
 			QFutureWatcher<EncodeThreadParameter_*>* futureWatcher = new QFutureWatcher<EncodeThreadParameter_*>();

+ 288 - 0
src/findresultview.cpp

@@ -0,0 +1,288 @@
+#include "findresultview.h"
+#include "styleset.h"
+#include "findresultwin.h"
+#include "ctipwin.h"
+#include "Scintilla.h"
+
+#include <QClipboard>
+
+
+const int MARGE_FOLDER = 1;
+const int STYLE_COLOUR_TITLE = 1;
+const int STYLE_COLOUR_DEST_FILE = 2;
+const int STYLE_COLOUR_KEYWORD_HIGH = 3;
+const int STYLE_COLOUR_KEYWORD_BACK_HIGH = 4;
+const int STYLE_DEEP_COLOUR_KEYWORD_HIGH = 5; //深色模式下面的前景色
+const int STYLE_DEEP_COLOUR_DEST_FILE = 6;
+
+static void getFoldColor(QColor& fgColor, QColor& bgColor, QColor& activeFgColor)
+{
+	//这里看起来反了,但是实际代码就是如此
+	fgColor = StyleSet::s_global_style->fold.bgColor;
+	bgColor = StyleSet::s_global_style->fold.fgColor;
+
+	activeFgColor = StyleSet::s_global_style->fold_active.fgColor;
+
+}
+
+void FindResultView::setFoldColor(int margin, QColor fgClack, QColor bkColor, QColor foreActive)
+{
+	SendScintilla(SCI_MARKERSETFORE, margin, fgClack);
+	SendScintilla(SCI_MARKERSETBACK, margin, bkColor);
+	SendScintilla(SCI_MARKERSETBACKSELECTED, margin, foreActive);
+}
+
+FindResultView::FindResultView(QWidget *parent)
+	: QsciScintilla(parent)
+{
+	//通过fold发现,尽量使用qscint的功能,因为他做了大量封装和简化
+	setFolding(BoxedTreeFoldStyle, MARGE_FOLDER);
+
+	SendScintilla(SCI_SETMARGINWIDTHN, MARGE_FOLDER, 14);
+
+	SendScintilla(SCI_MARKERSETFORE, SC_MARKNUM_FOLDERSUB, QColor(0xff,0,0));
+
+	setCaretLineVisible(true);
+	SendScintilla(SCI_SETSCROLLWIDTHTRACKING, true);
+	SendScintilla(SCI_SETCARETLINEBACK, StyleSet::s_global_style->current_line_background_color.bgColor);
+
+	QColor foldfgColor = Qt::white, foldbgColor = Qt::gray, activeFoldFgColor = Qt::red;
+	getFoldColor(foldfgColor, foldbgColor, activeFoldFgColor);
+	setFoldMarginColors(StyleSet::s_global_style->fold_margin.fgColor, StyleSet::s_global_style->fold_margin.bgColor);
+	setFoldColor(SC_MARKNUM_FOLDEROPEN, foldfgColor, foldbgColor, activeFoldFgColor);
+	setFoldColor(SC_MARKNUM_FOLDER, foldfgColor, foldbgColor, activeFoldFgColor);
+	setFoldColor(SC_MARKNUM_FOLDERSUB, foldfgColor, foldbgColor, activeFoldFgColor);
+	setFoldColor(SC_MARKNUM_FOLDERTAIL, foldfgColor, foldbgColor, activeFoldFgColor);
+	setFoldColor(SC_MARKNUM_FOLDEREND, foldfgColor, foldbgColor, activeFoldFgColor);
+	setFoldColor(SC_MARKNUM_FOLDEROPENMID, foldfgColor, foldbgColor, activeFoldFgColor);
+	setFoldColor(SC_MARKNUM_FOLDERMIDTAIL, foldfgColor, foldbgColor, activeFoldFgColor);
+
+	SendScintilla(SCI_STYLESETSIZE, STYLE_DEFAULT, 12);
+
+	if (!StyleSet::isCurrentDeepStyle())
+	{
+		this->setPaper(StyleSet::s_global_style->default_style.bgColor);
+
+		SendScintilla(SCI_STYLESETBACK, STYLE_COLOUR_TITLE, 0xffbbbb);
+		SendScintilla(SCI_STYLESETBACK, STYLE_COLOUR_DEST_FILE, 0xd5ffd5);
+		SendScintilla(SCI_STYLESETEOLFILLED, STYLE_COLOUR_TITLE, true);
+		SendScintilla(SCI_STYLESETEOLFILLED, STYLE_COLOUR_DEST_FILE, true);
+		SendScintilla(SCI_STYLESETFORE, STYLE_COLOUR_KEYWORD_HIGH, 0x4080ff);
+		SendScintilla(SCI_STYLESETBACK, STYLE_COLOUR_KEYWORD_BACK_HIGH, 0xbfffff);
+	
+	}
+	else
+	{
+		this->setColor(StyleSet::s_global_style->default_style.fgColor);
+		this->setPaper(StyleSet::s_global_style->default_style.bgColor);
+
+		//QColor& col = StyleSet::s_global_style->default_style.fgColor;
+		//sptr_t fgLParam = (col.blue() << 16) | (col.green() << 8) | col.red();
+
+		QColor& col2 = StyleSet::s_global_style->default_style.bgColor;
+		sptr_t bklParam = (col2.blue() << 16) | (col2.green() << 8) | col2.red();
+
+		SendScintilla(SCI_STYLESETBACK, STYLE_COLOUR_TITLE, 0xffbbbb); 
+		SendScintilla(SCI_STYLESETEOLFILLED, STYLE_COLOUR_TITLE, true);
+		//SendScintilla(SCI_STYLESETFORE, STYLE_COLOUR_TITLE, fgLParam);
+
+		SendScintilla(SCI_STYLESETBACK, STYLE_DEEP_COLOUR_DEST_FILE, bklParam);
+		SendScintilla(SCI_STYLESETFORE, STYLE_DEEP_COLOUR_DEST_FILE, 0x99cc99);
+		//SendScintilla(SCI_STYLESETFORE, STYLE_DEEP_COLOUR_DEST_FILE, fgLParam);
+		//SendScintilla(SCI_STYLESETBOLD, STYLE_DEEP_COLOUR_DEST_FILE, 1);//这个无法生效。可能是qscint bug
+
+		//文字要大一号,然后颜色是绿色
+		SendScintilla(SCI_STYLESETSIZE, STYLE_DEEP_COLOUR_DEST_FILE, 14);
+
+		SendScintilla(SCI_STYLESETFORE, STYLE_DEEP_COLOUR_KEYWORD_HIGH, 0x00aaff);
+		SendScintilla(SCI_STYLESETBACK, STYLE_DEEP_COLOUR_KEYWORD_HIGH, bklParam);
+
+
+		//给行号使用
+		SendScintilla(SCI_STYLESETFORE, STYLE_COLOUR_KEYWORD_HIGH, 0x4080ff);
+		SendScintilla(SCI_STYLESETBACK, STYLE_COLOUR_KEYWORD_HIGH, bklParam);
+	}
+
+
+	this->setReadOnly(true);
+
+	m_resultWin = dynamic_cast<FindResultWin*>(parent);
+}
+
+FindResultView::~FindResultView()
+{}
+
+//设置行背景色
+void FindResultView::setLineBackColorStyle(int line, int style)
+{
+	int startPos = SendScintilla(SCI_POSITIONFROMLINE, line);
+	int len = SendScintilla(SCI_LINELENGTH, line);
+
+	SendScintilla(SCI_STARTSTYLING, startPos);
+	SendScintilla(SCI_SETSTYLING, len, style);
+}
+
+//设置行前景色。line 行号,从相对行pos的位置开始
+void FindResultView::setLineColorStyle(int line, int offsetPos, int length, int style)
+{
+	int startPos = SendScintilla(SCI_POSITIONFROMLINE, line);
+	SendScintilla(SCI_STARTSTYLING, startPos + offsetPos);
+	SendScintilla(SCI_SETSTYLING, length, style);
+}
+
+
+void FindResultView::mouseDoubleClickEvent(QMouseEvent* /*e*/)
+{
+	//QsciScintilla::mouseDoubleClickEvent(e);
+
+	int line = 0;
+	int index = 0;
+
+	this->getCursorPosition(&line,&index);
+
+	emit lineDoubleClick(line);
+}
+
+void FindResultView::contextUserDefineMenuEvent(QMenu* menu)
+{
+	if (menu != nullptr)
+	{
+		//移动一下位置
+
+		QAction* pCopy =  menu->findChild<QAction*>("copy");
+		if (pCopy != nullptr)
+		{
+			menu->removeAction(pCopy);
+		}
+
+		menu->addAction(tr("Fold All"), this, &FindResultView::on_foldAll);
+		menu->addAction(tr("Expand All"), this, &FindResultView::on_expandAll);
+
+		menu->addSeparator();
+	
+		if (pCopy != nullptr)
+		{
+			menu->addAction(pCopy);
+		}
+		menu->addAction(tr("copy select line"), this, &FindResultView::on_copySelectLine);
+		menu->addAction(tr("warp"), this, &FindResultView::on_warp);
+
+		menu->addSeparator();
+
+		menu->addAction(tr("clear"), this, &FindResultView::on_clear);
+		menu->addAction(tr("close"), this, &FindResultView::on_close);
+
+
+	}
+	menu->move(cursor().pos()); //让菜单显示的位置在鼠标的坐标上
+	menu->show();
+}
+
+void FindResultView::on_foldAll()
+{
+	for (int i = 0; i < m_resultWin->m_resultLineInfo.size(); ++i)
+	{
+		const ResultLineInfo& lineInfo = m_resultWin->m_resultLineInfo.at(i);
+
+		//如果是1级别的行,则进行一个收起操作
+		if ((lineInfo.level == 1) || (lineInfo.level == 0))
+		{
+			SendScintilla(SCI_FOLDLINE, i, (long)SC_FOLDACTION_CONTRACT);
+		}
+	}
+}
+
+void FindResultView::on_expandAll()
+{
+	for (int i = 0; i < m_resultWin->m_resultLineInfo.size(); ++i)
+	{
+		const ResultLineInfo& lineInfo = m_resultWin->m_resultLineInfo.at(i);
+
+		//如果是1级别的行,则进行一个收起操作
+		if ((lineInfo.level == 1) || (lineInfo.level == 0))
+		{
+			SendScintilla(SCI_FOLDLINE, i, SC_FOLDACTION_EXPAND);
+		}
+	}
+}
+
+//复制选中的内容
+//void FindResultView::on_copySelect()
+//{
+//	QString word = selectedText();
+//	if (!word.isEmpty())
+//	{
+//		QClipboard* clipboard = QApplication::clipboard();
+//		clipboard->setText(word);
+//
+//		CTipWin::showTips(this, tr("Copy to clipboard Finished!"), 1200,true);
+//	}
+//}
+
+//复制选中行
+void FindResultView::on_copySelectLine()
+{
+	int startPos = SendScintilla(SCI_GETSELECTIONSTART);
+	int endPos = SendScintilla(SCI_GETSELECTIONEND);
+
+	int startLine = SendScintilla(SCI_LINEFROMPOSITION, startPos);
+	int endLine = SendScintilla(SCI_LINEFROMPOSITION, endPos);
+
+	int start = SendScintilla(SCI_POSITIONFROMLINE, startLine);
+	int end = SendScintilla(SCI_POSITIONFROMLINE, endLine+1);
+
+	char *dest = new char[end - start + 1];
+	dest[end - start] = '\0';
+
+	Sci_TextRange tr;
+	tr.chrg.cpMin = static_cast<Sci_PositionCR>(start);
+	tr.chrg.cpMax = static_cast<Sci_PositionCR>(end);
+	tr.lpstrText = dest;
+
+	this->SendScintilla(SCI_GETTEXTRANGE, 0, &tr);
+
+	QString text(dest);
+
+	QStringList lineText = text.split("\n");
+	QString selectConnect;
+
+	for (int i = 0; i < lineText.size(); ++i)
+	{
+		const QString& t = lineText.at(i);
+		int pos = t.indexOf(": ");
+		if (pos != -1)
+		{
+			QString v = t.mid(pos + 2);
+			selectConnect.append(v);
+			selectConnect.append("\n");
+		}
+	}
+
+	QClipboard* clipboard = QApplication::clipboard();
+	clipboard->setText(selectConnect);
+
+	//CTipWin::showTips(this, tr("Copy to clipboard Finished!"), 1200, true);
+}
+
+void  FindResultView::on_clear()
+{
+	this->clear();
+	m_resultWin->clear();
+}
+
+void  FindResultView::on_close()
+{
+	m_resultWin->m_parent->close();
+}
+
+void  FindResultView::on_warp()
+{
+	if (SC_WRAP_CHAR != wrapMode())
+	{
+		this->setWrapMode(QsciScintilla::WrapCharacter);
+	}
+	else
+	{
+		this->setWrapMode(QsciScintilla::WrapNone);
+	}
+}

+ 49 - 0
src/findresultview.h

@@ -0,0 +1,49 @@
+#pragma once
+#include <QWidget>
+#include <qsciscintilla.h>
+#include <QMouseEvent>
+#include <QMenu>
+
+extern const int MARGIN_VER_LINE;
+extern const int STYLE_COLOUR_TITLE;
+extern const int STYLE_COLOUR_DEST_FILE;
+extern const int STYLE_COLOUR_KEYWORD_HIGH;
+extern const int STYLE_COLOUR_KEYWORD_BACK_HIGH;
+extern const int STYLE_DEEP_COLOUR_KEYWORD_HIGH;
+extern const int STYLE_DEEP_COLOUR_DEST_FILE;
+
+class FindResultWin;
+
+class FindResultView  : public QsciScintilla
+{
+	Q_OBJECT
+
+public:
+	FindResultView(QWidget* parent);
+	virtual ~FindResultView();
+
+	void setLineBackColorStyle(int line, int style);
+	void setLineColorStyle(int line, int pos, int length, int style);
+
+signals:
+	void lineDoubleClick(int line);
+
+public slots:
+	void on_foldAll();
+private slots:
+
+	void on_expandAll();
+	//void on_copySelect();
+	void on_copySelectLine();
+	void on_clear();
+	void on_close();
+	void on_warp();
+
+protected:
+	void mouseDoubleClickEvent(QMouseEvent* e) override;
+	void contextUserDefineMenuEvent(QMenu* menu) override;
+	void setFoldColor(int margin, QColor fgClack, QColor bkColor, QColor foreActive);
+
+private:
+	FindResultWin* m_resultWin;
+};

+ 190 - 458
src/findresultwin.cpp

@@ -3,19 +3,20 @@
 #include "common.h"
 #include "styleset.h"
 #include "nddsetting.h"
+#include "findresultview.h"
 
-#include <QTreeWidgetItem>
-#include <QStyleFactory>
-#include <QToolButton>
-#include <qtreeview.h>
-#include <QStandardItem> 
-#include <QStandardItemModel>
+#include <qsciscintilla.h>
+#include <Scintilla.h>
+
+//#include <QTreeWidgetItem>
+//#include <QStyleFactory>
+//#include <QToolButton>
+//#include <qtreeview.h>
+//#include <QStandardItem> 
+//#include <QStandardItemModel>
 #include <QClipboard>
 #include <QTextEdit>
 #include <qscrollbar.h>
-
-#include "ndstyleditemdelegate.h"
-
 //目前可以高亮,使用富文本进行了高亮设置。但是有个问题:富文本与html有一些冲突,在<>存在时,可能导致乱。这是一个问题。20220609
 //使用Html的转义解决了该问题
 
@@ -23,51 +24,8 @@ FindResultWin::FindResultWin(QWidget *parent)
 	: QWidget(parent), m_menu(nullptr), m_parent(parent),m_defaultFontSize(14), m_defFontSizeChange(false)
 {
 	ui.setupUi(this);
-
-	//设置左边的缩起来按钮为加号,而不是箭头
-	ui.resultTreeView->setStyle(QStyleFactory::create("windows"));
-	ui.resultTreeView->header()->hide();
+	connect(ui.displayView, &FindResultView::lineDoubleClick, this, &FindResultWin::on_lineDoubleClick);
 	
-	m_model = new QStandardItemModel(ui.resultTreeView);
-	m_delegate = new NdStyledItemDelegate(ui.resultTreeView);
-	ui.resultTreeView->setModel(m_model);
-	ui.resultTreeView->setItemDelegate(m_delegate);
-	ui.resultTreeView->setEditTriggers(QAbstractItemView::NoEditTriggers);
-	ui.resultTreeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
-
-//#if defined (Q_OS_MAC)
-//	QString qss = "QTreeView::item:selected{ \
-//	   background:#e8e8ff; \
-//    } \
-//    QTreeView::item{ \
-//        height:18px; \
-//    }";
-//#else
-//    QString qss = "QTreeView::item:selected{ \
-//       background:#e8e8ff; \
-//    }";
-//#endif
-//	ui.resultTreeView->setStyleSheet(qss);
-
-	connect(ui.resultTreeView, &QTreeView::doubleClicked, this, &FindResultWin::itemDoubleClicked);
-
-	connect(ui.resultTreeView, SIGNAL(pressed(QModelIndex)), this, SLOT(slot_treeView_pressed(QModelIndex)));
-	connect(ui.resultTreeView, SIGNAL(expanded(QModelIndex)), this, SLOT(slot_treeView_pressed(QModelIndex)));
-
-	ui.resultTreeView->verticalScrollBar()->setStyle(QStyleFactory::create("vis"));
-	ui.resultTreeView->horizontalScrollBar()->setStyle(QStyleFactory::create("vis"));
-
-	int defFontSize = NddSetting::getKeyValueFromNumSets(FIND_RESULT_FONT_SIZE);
-	if (defFontSize >= 8)
-	{
-		m_defaultFontSize = defFontSize;
-
-		QFont curFt = ui.resultTreeView->font();
-		curFt.setPointSize(m_defaultFontSize);
-		ui.resultTreeView->setFont(curFt);
-
-		m_delegate->setFontSize(m_defaultFontSize);
-}
 }
 
 FindResultWin::~FindResultWin()
@@ -75,311 +33,32 @@ FindResultWin::~FindResultWin()
 	if (m_defFontSizeChange)
 	{
 		NddSetting::updataKeyValueFromNumSets(FIND_RESULT_FONT_SIZE, m_defaultFontSize);
-}
-}
-
-void FindResultWin::slot_treeView_pressed(QModelIndex modeIndex)
-{
-	ui.resultTreeView->resizeColumnToContents(modeIndex.column());
-}
-
-void FindResultWin::contextMenuEvent(QContextMenuEvent *)
-{
-	if (m_menu == nullptr)
-	{
-		m_menu = new QMenu(this);
-		m_menu->addAction(tr("clear this find result"), this, &FindResultWin::slot_clearContents);
-		m_menu->addAction(tr("clear all find result"), this, &FindResultWin::slot_clearAllContents);
-
-		m_menu->addSeparator();
-		m_pSelectSectonAct = m_menu->addAction(tr("select section"), this, &FindResultWin::slot_selectSection);
-		m_menu->addAction(tr("select all item"), this, &FindResultWin::slot_selectAll);
-
-		m_menu->addSeparator();
-
-		m_menu->addAction(tr("copy select item (Ctrl Muli)"), this, &FindResultWin::slot_copyItemContents);
-		m_menu->addAction(tr("copy select Line (Ctrl Muli)"), this, &FindResultWin::slot_copyContents);
-
-		m_menu->addSeparator();
-		m_menu->addAction(tr("Zoom In"), this, &FindResultWin::slot_fontZoomIn);
-		m_menu->addAction(tr("Zoom Out"), this, &FindResultWin::slot_fontZoomOut);
-		m_menu->addAction(tr("close"), m_parent, &QWidget::close);
-
-	}
-	m_menu->move(cursor().pos()); //让菜单显示的位置在鼠标的坐标上
-	m_menu->show();
-
-	QModelIndex curSelItem = ui.resultTreeView->currentIndex();
-
-	if (!curSelItem.data(ResultItemRoot).isNull())
-	{
-		//是根不能选择section
-		m_pSelectSectonAct->setEnabled(false);
-}
-	else if (!curSelItem.data(ResultItemEditor).isNull())
-	{
-		m_pSelectSectonAct->setEnabled(true);
-	}
-	else if (!curSelItem.data(ResultItemPos).isNull())
-	{
-		m_pSelectSectonAct->setEnabled(true);
-	}
-}
-
-void FindResultWin::slot_clearContents()
-{
-	QModelIndex curSelItem = ui.resultTreeView->currentIndex();
-
-	if (!curSelItem.data(ResultItemRoot).isNull())
-	{
-		//是根可以直接删除
-		m_model->removeRow(curSelItem.row());
 	}
-	else if (!curSelItem.data(ResultItemEditor).isNull())
-	{
-		//需要找到上一个父节点,即根
-		QModelIndex rootItem = curSelItem.parent();
-
-		if (rootItem.isValid())
-		{
-			m_model->removeRow(curSelItem.row(), rootItem);
 
-			if (0 == m_model->rowCount(rootItem))
-			{
-				m_model->removeRow(rootItem.row());
-			}
-		}
-	}
-	else if (!curSelItem.data(ResultItemPos).isNull())
-	{
-		//需要找到上两个父节点,即根
-		QModelIndex itemEditor = curSelItem.parent();
-		if (itemEditor.isValid())
-		{
-			QModelIndex rootItem = itemEditor.parent();
-			if (rootItem.isValid())
-			{
-				m_model->removeRow(itemEditor.row(), rootItem);
-				if (0 == m_model->rowCount(rootItem))
-				{
-					m_model->removeRow(rootItem.row());
-				}
-			}
-		}
-	}
+	clear();
 }
 
-//全选
-void FindResultWin::slot_selectAll()
+void FindResultWin::clear()
 {
-
-	QModelIndex root = ui.resultTreeView->rootIndex();
-
-	QModelIndex curSelItem = ui.resultTreeView->currentIndex();
-	QModelIndex firstRootItem;
-	//先找到根节点
-	while (curSelItem.isValid())
+	for (int i = 0; i < m_resultLineFilePath.size(); ++i)
 	{
-		QModelIndex pMi = curSelItem.parent();
-		if (pMi.isValid())
-		{
-			curSelItem = pMi;
-}
-		else
-		{
-			break;
-		}
-	}
-
-	//找到第一个兄弟根节点
-	if (curSelItem.row() != 0)
-	{
-		firstRootItem = curSelItem.siblingAtRow(0);
-	}
-	else
-	{
-		firstRootItem = curSelItem;
-	}
-
-	auto selectSection = [this](QModelIndex& sectionItem)->int{
-		//遍历其下面的所有子节点
-		ui.resultTreeView->selectionModel()->select(sectionItem, QItemSelectionModel::Select);
-
-		//遍历下面的子节点
-		int i = 0;
-		QModelIndex childMi;
-        childMi = sectionItem.model()->index(i, 0, sectionItem);
-		while (childMi.isValid())
-		{
-			++i;
-			ui.resultTreeView->selectionModel()->select(childMi, QItemSelectionModel::Select);
-            childMi = sectionItem.model()->index(i, 0, sectionItem);
-		}
-		return i+1;
-	};
-
-	QModelIndex rootItem = firstRootItem;
-	int j = 0;
-	int selectCount = 0;
-	while (rootItem.isValid())
-	{
-		//遍历根节点下面每一个section
-		{
-			int i = 0;
-            QModelIndex section = rootItem.model()->index(i, 0, rootItem);
-			while (section.isValid() && !section.data(ResultItemEditor).isNull())
-			{
-				++i;
-				selectCount += selectSection(section);
-                section = firstRootItem.model()->index(i, 0, firstRootItem);
-			}
-		}
-
-		//切换到下一个查找的根节点
-		j++;
-		rootItem = firstRootItem.siblingAtRow(j);
-	}
-
-	QString msg = tr("%1 rows selected !").arg(selectCount);
-	emit showMsg(msg);
-}
-
-void FindResultWin::slot_selectSection()
-{
-	QModelIndex curSelItem = ui.resultTreeView->currentIndex();
-
-	auto selectSection = [this](QModelIndex& sectionItem)->int {
-		//遍历其下面的所有子节点
-		ui.resultTreeView->selectionModel()->select(sectionItem, QItemSelectionModel::Select);
-
-		//遍历下面的子节点
-		int i = 0;
-		QModelIndex childMi;
-        childMi = sectionItem.model()->index(i, 0, sectionItem);
-		while (childMi.isValid())
-		{
-			++i;
-			ui.resultTreeView->selectionModel()->select(childMi, QItemSelectionModel::Select);
-			childMi = sectionItem.model()->index(i, 0, sectionItem);
-		}
-		return i+1;
-	};
-
-	int selectCount = 0;
-
-	if (!curSelItem.data(ResultItemRoot).isNull())
-	{
-		//啥也不做。不能选择多个section
-	}
-	else if (!curSelItem.data(ResultItemEditor).isNull())
-	{
-		selectCount = selectSection(curSelItem);
-		
-	}
-	else if (!curSelItem.data(ResultItemPos).isNull())
-	{
-		//其父节点
-		QModelIndex sectionItem = curSelItem.parent();
-		if (!sectionItem.data(ResultItemEditor).isNull())
-		{
-			selectCount = selectSection(sectionItem);
-		}
-	}
-
-	QString msg = tr("%1 rows selected !").arg(selectCount);
-	emit showMsg(msg);
-}
-
-//拷贝item的行,不进行过滤,全部拷贝
-void FindResultWin::slot_copyItemContents()
-{
-	QModelIndexList selectList;
-
-	ui.resultTreeView->getSelectedIndexes(selectList);
-
-	QString selectConnect;
-
-	for (int i = 0, s = selectList.size(); i < s; ++i)
-	{
-
-		QModelIndex curSelItem = selectList.at(i);
-
-		QString text = m_model->itemData(curSelItem).values()[0].toString();
-
-		QTextEdit t(this);
-		t.setAcceptRichText(true);
-		t.setText(text);
-		text = t.toPlainText();
-
-		selectConnect.append(text);
-		selectConnect.append("\n");
-	}
-
-	QClipboard *clip = QApplication::clipboard();
-	clip->setText(selectConnect);
-
-	QString msg = tr("%1 items have been copied to the clipboard !").arg(selectList.size());
-	emit showMsg(msg);
-}
-
-void FindResultWin::slot_copyContents()
-{
-	QModelIndexList selectList;
-
-	//std::sort(selectList.begin(), selectList.end(), [](QModelIndex& a, QModelIndex& b) {
-	//	return a.row() < b.row();
-	//});
-	
-	ui.resultTreeView->getSelectedIndexes(selectList);
-
-	QString selectConnect;
-
-	int copyTimes = 0;
-
-	for (int i = 0, s = selectList.size(); i < s; ++i)
-	{
-		QModelIndex curSelItem = selectList.at(i);
-
-		//只拷贝真正的行内容
-		if (curSelItem.data(ResultItemPos).isNull())
-		{
-			continue;
-		}
-
-		copyTimes++;
-
-	QString text = m_model->itemData(curSelItem).values()[0].toString();
-
-	QTextEdit t(this);
-	t.setAcceptRichText(true);
-	t.setText(text);
-	text = t.toPlainText();
-
-		int pos = text.indexOf(": ");
-		if (pos != -1)
-		{
-			text = text.mid(pos + 2);
-		}
-
-		selectConnect.append(text);
-		selectConnect.append("\n");
+		delete m_resultLineFilePath.at(i);
 	}
-
-	QClipboard *clip = QApplication::clipboard();
-	clip->setText(selectConnect);
-
-	QString msg = tr("%1 lines have been copied to the clipboard !").arg(copyTimes);
-	emit showMsg(msg);
+	m_resultLineFilePath.clear();
+	m_resultLineInfo.clear();
 }
 
 void FindResultWin::slot_clearAllContents()
 {
-	m_model->clear();
+	clear();
+	ui.displayView->clear();
 }
 
+#if 0 //老的机制,暂时屏蔽,后续可删除
 //高亮查找的关键字文本。Index表示是第几次出现,前面的要跳过
 void FindResultWin::highlightFindText(int index, QString &srcText, QString &findText, Qt::CaseSensitivity cs)
 {
+#if 0
 	int pos = 0;
 	int findPos = 0;
 
@@ -403,14 +82,18 @@ void FindResultWin::highlightFindText(int index, QString &srcText, QString &find
 		index--;
 	}
 	srcText.replace(pos, lens, QString("<font style='font-size:14px;background-color:#ffffbf'>%1</font>").arg(srcText.mid(pos,lens)));
+#endif
 }
+#endif
 
 const int MAX_HEAD_LENTGH = 20;
 const int MAX_TAIL_LENGTH = 80;
 
+#if 0
 //更复杂的高亮:在全词语匹配,大小写敏感,甚至正则表达式情况下,上面的highlightFindText是不够的。需要精确定位
 QString FindResultWin::highlightFindText(FindRecord& record)
 {
+#if 0
 	QByteArray utf8bytes = record.lineContents.toUtf8();
 
 	int lineLens = utf8bytes.length();
@@ -438,9 +121,9 @@ QString FindResultWin::highlightFindText(FindRecord& record)
 			head = QString("<font style='font-size:14px;'>%1</font>").arg(QString(utf8bytes.mid(0, targetStart)).toHtmlEscaped());
 			src = QString("<font style='font-size:14px;background-color:#ffffbf'>%1</font>").arg(QString(utf8bytes.mid(targetStart, targetLens)).toHtmlEscaped());
 			tail = QString("<font style='font-size:14px;'>%1</font>").arg(QString(utf8bytes.mid(tailStart)).toHtmlEscaped());
-	}
-	else
-	{
+		}
+		else
+		{
 			head = QString(utf8bytes.mid(0, targetStart));
 			if (head.size() > MAX_HEAD_LENTGH)
 			{
@@ -471,7 +154,7 @@ QString FindResultWin::highlightFindText(FindRecord& record)
 			head = QString("<font style='font-size:14px;color:#dcdcdc'>%1</font>").arg(QString(utf8bytes.mid(0, targetStart)).toHtmlEscaped());
 			src = QString("<font style='font-size:14px;font-weight:bold;color:#ffaa00'>%1</font>").arg(QString(utf8bytes.mid(targetStart, targetLens)).toHtmlEscaped());
 			tail = QString("<font style='font-size:14px;color:#dcdcdc'>%1</font>").arg(QString(utf8bytes.mid(tailStart)).toHtmlEscaped());
-	}
+		}
 		else
 		{
 			QString headContens = QString(utf8bytes.mid(0, targetStart));
@@ -501,36 +184,68 @@ QString FindResultWin::highlightFindText(FindRecord& record)
 	}
 
 	return QString("%1%2%3").arg(head).arg(src).arg(tail);
+#endif
+	return "";
 }
 
+
+//在当前文件查找字段,结果是一个单一的FindRecords
 void FindResultWin::appendResultsToShow(FindRecords* record)
 {
+#if 0
 	if (record == nullptr)
 	{
 		return;
 	}
+	FindResultView* pDisplay = ui.displayView;
 
-	QString findTitle;
-	//if (!StyleSet::isCurrentDeepStyle())
-	//{
-		findTitle = tr("<font style='font-size:14px;font-weight:bold;color:#343497'>Search \"%1\" (%2 hits)</font>").arg(record->findText.toHtmlEscaped()).arg(record->records.size());
-	/*}
-	else
+	QString findTitle = tr("Search \"%1\" (%2 hits)\n").arg(record->findText).arg(record->records.size());
+
+	//pDisplay->append(findTitle);
+
+	pDisplay->insertAt(findTitle,0,0);
+
+	pDisplay->SendScintilla(SCI_SETFOLDLEVEL, 0, (long)(0|SC_FOLDLEVELHEADERFLAG));
+
+	QStringList contents;
+
+	for (int i = 0; i < record->records.size(); ++i)
 	{
-		findTitle = tr("<font style='font-size:14px;font-weight:bold;color:#ffffff'>Search \"%1\" (%2 hits)</font>").arg(record->findText.toHtmlEscaped()).arg(record->records.size());
-	}*/
+		FindRecord v = record->records.at(i);
 
+		const QString & richText = v.lineContents;
 
-	QStandardItem* titleItem = new QStandardItem(findTitle);
+		QString text;
+		if (!StyleSet::isCurrentDeepStyle())
+		{
+			text = tr("Line %1 : %2\n").arg(v.lineNum + 1).arg(richText);
+		}
+		else
+		{
+			text = tr("Line %1 : %2\n").arg(v.lineNum + 1).arg(richText);
+		}
+
+		contents.append(text);
+	}
+
+	pDisplay->insertAt(contents.join(""), 1, 0);
+
+	for (int i = 0; i < record->records.size(); ++i)
+	{
+		pDisplay->SendScintilla(SCI_SETFOLDLEVEL, i+1, 1);
+	}
+#endif
+
+#if 0
+	
+
+	QString findTitle;
+
+	findTitle = tr("<font style='font-size:14px;font-weight:bold;color:#343497'>Search \"%1\" (%2 hits)</font>").arg(record->findText.toHtmlEscaped()).arg(record->records.size());
 
-	//if (!StyleSet::isCurrentDeepStyle())
-	//{
-		setItemBackground(titleItem, QColor(0xbbbbff));
-	//}
-	//else
-	//{
-	//	setItemBackground(titleItem, QColor(0x423328));//0xd5ffd5
-	//}
+	QStandardItem* titleItem = new QStandardItem(findTitle);
+	setItemBackground(titleItem, QColor(0xbbbbff));
+	
 
 	m_model->insertRow(0, titleItem);
 	titleItem->setData(QVariant(true), ResultItemRoot);
@@ -579,8 +294,6 @@ void FindResultWin::appendResultsToShow(FindRecords* record)
 	//描述行双击不响应
 	descItem->setData(QVariant(true), ResultItemDesc);
 
-	//int lastLineNum = -1;
-	//int occurTimes = 0;
 
 	for (int i =0 ; i < record->records.size(); ++i)
 	{
@@ -609,8 +322,9 @@ void FindResultWin::appendResultsToShow(FindRecords* record)
 	{
 		ui.resultTreeView->expand(m_model->index(0, 0, m_model->index(0, 0)));
 	}
-
+#endif
 }
+#endif
 
 void FindResultWin::appendResultsToShow(QVector<FindRecords*>* record, int hits, QString whatFind)
 {
@@ -619,149 +333,149 @@ void FindResultWin::appendResultsToShow(QVector<FindRecords*>* record, int hits,
 		return;
 	}
 
-	QString findTitle = tr("<font style='font-size:14px;font-weight:bold;color:#343497'>Search \"%1\" (%2 hits in %3 files)</font>").arg(whatFind.toHtmlEscaped()).arg(hits).arg(record->size());
-	QStandardItem* titleItem = new QStandardItem(findTitle);
-	setItemBackground(titleItem, QColor(0xbbbbff));
-	titleItem->setData(QVariant(true), ResultItemRoot);
+	if (this->isHidden())
+	{
+		this->setVisible(true);
+	}
 
-	//总是把结果插在最上面一行
-	m_model->insertRow(0, titleItem);
+	ResultLineInfo lineInfo;
 
-	int rowNum = m_model->rowCount();
+	QString findTitle = tr("Search \"%1\" (%2 hits in %3 files)\n").arg(whatFind).arg(hits).arg(record->size());
 
-	//把其余的行收起来
-	for (int i = 1; i < rowNum; ++i)
-	{
-		ui.resultTreeView->collapse(m_model->index(i, 0));
-	}
-	ui.resultTreeView->expand(m_model->index(0, 0));
+	FindResultView* pDisplay = ui.displayView;
+	pDisplay->on_foldAll();
+
+	pDisplay->insertAt(findTitle, 0, 0);
+
+	lineInfo.level = 0;
+	m_resultLineInfo.insert(0,lineInfo);
+
+	pDisplay->SendScintilla(SCI_SETFOLDLEVEL, 0, (long)(0 | SC_FOLDLEVELHEADERFLAG));
 
 	if (record->size() == 0)
 	{
 		return;
 	}
 
+	QStringList contents;
 
+	QList<int> keyworkOffsetPos;
+	QString text;
+	QString linePrefix;
 
-	for (int i = 0,count= record->size(); i < count; ++i)
+
+	int insertIndex = 1;
+	for (int i = 0, count = record->size(); i < count; ++i)
 	{
 		FindRecords* pr = record->at(i);
 
+		QString* pFilePath = new QString(pr->findFilePath);
 		QString desc;
 		if (!StyleSet::isCurrentDeepStyle())
 		{
-			desc = tr("<font style='font-size:14px;font-weight:bold;color:#309730'>%1 (%2 hits)</font>").arg(pr->findFilePath.toHtmlEscaped()).arg(pr->records.size());
-		}
-		else
-		{
-			desc = tr("<font style='font-size:14px;color:#99cc99'>%1 (%2 hits)</font>").arg(pr->findFilePath.toHtmlEscaped()).arg(pr->records.size());
-		}
-
-		QStandardItem* descItem = new QStandardItem(desc);
-
-		if (!StyleSet::isCurrentDeepStyle())
-		{
-		setItemBackground(descItem, QColor(0xd5ffd5));
+			desc = tr(" %1 (%2 hits)\n").arg(pr->findFilePath).arg(pr->records.size());
 		}
 		else
 		{
-			setItemBackground(descItem, QColor(0x484848));
+			desc = tr(" %1 (%2 hits)\n").arg(pr->findFilePath).arg(pr->records.size());
 		}
+		contents.append(desc);
+		m_resultLineFilePath.append(pFilePath);
 
-		titleItem->insertRow(0,descItem);
+		lineInfo.level = 1;
+		m_resultLineInfo.insert(insertIndex, lineInfo);
+		++insertIndex;
 
-		//默认全部收起来
-		if (count > 10)
+		for (int j = 0; j < pr->records.size(); ++j)
 		{
-			ui.resultTreeView->collapse(m_model->index(0, 0, m_model->index(0, 0)));
-		}
-	
-		descItem->setData(QVariant((qlonglong)pr->pEdit), ResultItemEditor);
-		descItem->setData(QVariant(pr->findFilePath), ResultItemEditorFilePath);
-		descItem->setData(QVariant(pr->findText), ResultWhatFind);
+			FindRecord  v = pr->records.at(j);
+			QString richText = v.lineContents;
 
-		//描述行双击不响应
-		descItem->setData(QVariant(true), ResultItemDesc);
-
-		for (int i = 0; i < pr->records.size(); ++i)
-		{
-			FindRecord  v = pr->records.at(i);
-			QString richText = highlightFindText(v);
+			linePrefix = tr("    Line %1: ").arg(v.lineNum + 1);
 
-			QString text;
 			if (!StyleSet::isCurrentDeepStyle())
 			{
-				text = tr("<font style='font-size:14px;'>Line </font><font style='font-size:14px;color:#ff8040'>%1</font> : %2").arg(v.lineNum + 1).arg(richText);
+				text = tr("%1%2\n").arg(linePrefix).arg(richText);
 			}
 			else
 			{
-				text = tr("<font style='font-size:14px;color:#ffffff'>Line </font><font style='font-size:14px;color:#ff8040'>%1</font> : %2").arg(v.lineNum + 1).arg(richText);
+				text = tr("%1%2\n").arg(linePrefix).arg(richText);
 			}
-			QStandardItem* childItem = new QStandardItem(text);
-#if defined(Q_OS_MAC)
-        childItem->setTextAlignment(Qt::AlignVCenter);
-#endif
-			childItem->setData(QVariant(v.pos), ResultItemPos);
-			childItem->setData(QVariant(v.end - v.pos), ResultItemLen);
-			descItem->appendRow(childItem);
+			contents.append(text);
+			keyworkOffsetPos.append(linePrefix.toUtf8().size());
+			lineInfo.level = 2;
+			lineInfo.resultPos = v.pos;
+			lineInfo.resultEnd = v.end;
+			lineInfo.pFilePath = pFilePath;
+			m_resultLineInfo.insert(insertIndex, lineInfo);
+			++insertIndex;
 
 			QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
 		}
-		if (count <= 10 && !pr->records.isEmpty())
-		{
-			ui.resultTreeView->expand(m_model->index(0, 0, m_model->index(0, 0)));
-		}
 	}
-	ui.resultTreeView->expand(m_model->index(0, 0, m_model->index(0, 0)));
-}
 
-void FindResultWin::setItemBackground(QStandardItem* item, const QColor& color)
-{
-	QBrush b(color);
-	item->setBackground(b);
-}
+	pDisplay->insertAt(contents.join(""), 1, 0);
+	
+	int lineNum = 1;
 
-void FindResultWin::setItemForeground(QStandardItem* item, const QColor& color)
-{
-	QBrush b(color);
-	item->setForeground(b);
-}
+	QList<int> destFileLineNum;
 
-//查找结果框的字体变大
-void FindResultWin::slot_fontZoomIn()
-{
-	QFont curFt = ui.resultTreeView->font();
+	for (int i = 0, count = record->size(); i < count; ++i)
+	{
+		FindRecords* pr = record->at(i);
 
-	int s = curFt.pointSize();
-	s += 2;
-	curFt.setPointSize(s);
+		pDisplay->SendScintilla(SCI_SETFOLDLEVEL, lineNum, (long)(1 | SC_FOLDLEVELHEADERFLAG));
+		destFileLineNum.append(lineNum);
+		++lineNum;
 
-	m_defaultFontSize += 2;
+		for (int j = 0; j < pr->records.size(); ++j)
+		{
+			pDisplay->SendScintilla(SCI_SETFOLDLEVEL, lineNum, (long)2| SC_FOLDLEVELBASE);
 
-	ui.resultTreeView->setFont(curFt);
+			++lineNum;
+		}
+	}
 
-	m_delegate->setFontSize(m_defaultFontSize);
+	//着色
+	pDisplay->setLineBackColorStyle(0, STYLE_COLOUR_TITLE);
 
-	m_defFontSizeChange = true;
-}
+	for (int i = 0, count = destFileLineNum.size(); i < count; ++i)
+	{
+		pDisplay->setLineBackColorStyle(destFileLineNum.at(i), (StyleSet::isCurrentDeepStyle()? STYLE_DEEP_COLOUR_DEST_FILE:STYLE_COLOUR_DEST_FILE));
+	}
+	
+	//关键字高亮
+	//高亮的开始、结束位置
+	int targetStart = 0;
+	int targetLens = 0;
+	lineNum = 1;
 
-void FindResultWin::slot_fontZoomOut()
-{
-	QFont curFt = ui.resultTreeView->font();
+	int lineOffsetPosIndex = 0;
+	int lineOffsetPos = 0;
 
-	int s = curFt.pointSize();
-	s -= 2;
+	QString lineNumStr = tr("    Line ");
+	int skipLineNumOffset = lineNumStr.toUtf8().size();
 
-	if (s >= 8)
+	for (int i = 0, count = record->size(); i < count; ++i)
 	{
-		m_defFontSizeChange = true;
-		m_defaultFontSize -= 2;
-		curFt.setPointSize(s);
-		ui.resultTreeView->setFont(curFt);
-		m_delegate->setFontSize(m_defaultFontSize);
+		FindRecords* pr = record->at(i);
+		++lineNum;
+		for (int j = 0; j < pr->records.size(); ++j)
+		{
+			lineOffsetPos = keyworkOffsetPos.at(lineOffsetPosIndex);
+			const FindRecord &v = pr->records.at(j);
+			targetStart = v.pos - v.lineStartPos + lineOffsetPos;
+			targetLens = v.end - v.pos;
+			pDisplay->setLineColorStyle(lineNum, skipLineNumOffset, lineOffsetPos-skipLineNumOffset-2, STYLE_COLOUR_KEYWORD_HIGH);
+			pDisplay->setLineColorStyle(lineNum, targetStart, targetLens, (StyleSet::isCurrentDeepStyle()? STYLE_DEEP_COLOUR_KEYWORD_HIGH:STYLE_COLOUR_KEYWORD_BACK_HIGH));
+			++lineNum;
+			++lineOffsetPosIndex;
+		}
 	}
+	pDisplay->SendScintilla(SCI_GOTOLINE, 0);
 }
 
+
 int FindResultWin::getDefaultFontSize()
 {
 	return m_defaultFontSize;
@@ -771,3 +485,21 @@ void FindResultWin::setDefaultFontSize(int defSize)
 {
 	m_defaultFontSize = defSize;
 }
+
+void FindResultWin::on_lineDoubleClick(int lineNum)
+{
+	if (lineNum < m_resultLineInfo.size())
+	{
+		const ResultLineInfo& lineInfo = m_resultLineInfo.at(lineNum);
+
+		if (lineInfo.level == 2)
+		{
+			//文件定位到行
+			emit lineDoubleClicked(lineInfo.pFilePath, lineInfo.resultPos, lineInfo.resultEnd);
+		}
+		else if ((lineInfo.level == 0) || (lineInfo.level == 1))
+		{
+			ui.displayView->SendScintilla(SCI_FOLDLINE, lineNum, SC_FOLDACTION_TOGGLE);
+		}
+	}
+}

+ 17 - 20
src/findresultwin.h

@@ -1,4 +1,4 @@
-锘�#pragma once
+#pragma once
 
 #include <QWidget>
 #include <QContextMenuEvent>
@@ -6,57 +6,54 @@
 #include "ui_findresultwin.h"
 
 class FindRecords;
-class QStandardItem;
-class NdStyledItemDelegate;
-class QStandardItemModel;
 struct FindRecord;
 
+struct ResultLineInfo {
+	int level;//缩进类型。0 1 2。0:title 1 filepath desc 2 result。
+	int resultPos;//结果字段的开始offset。0和1是没有这个字段的。
+	int resultEnd;//长度
+	QString* pFilePath;
+};
+
 class FindResultWin : public QWidget
 {
 	Q_OBJECT
 
 public:
+	friend class FindResultView;
 	FindResultWin(QWidget *parent = Q_NULLPTR);
 	~FindResultWin();
 
-	void appendResultsToShow(FindRecords * record);
 	void appendResultsToShow(QVector<FindRecords*>* record, int hits, QString whatFind);
 	int  getDefaultFontSize();
 	void setDefaultFontSize(int defSize);
+	void clear();
 signals:
 	void itemDoubleClicked(const QModelIndex &index);
 	void showMsg(QString &msg);
+	void lineDoubleClicked(QString* pFilePath, int pos, int end);
 
 private slots:
-	void slot_clearContents();
-	void slot_selectAll();
-	void slot_copyContents();
-	void slot_copyItemContents();
-	void slot_selectSection();
-	void slot_treeView_pressed(QModelIndex modeIndex);
-	void slot_fontZoomIn();
-	void slot_fontZoomOut();
+	void on_lineDoubleClick(int line);
 public slots:
 	void slot_clearAllContents();
 
-protected:
-	void contextMenuEvent(QContextMenuEvent * event);
-
 private:
+#if 0
 	void setItemBackground(QStandardItem* item, const QColor& color);
 	void setItemForeground(QStandardItem * item, const QColor & color);
 
 	void highlightFindText(int index, QString & srcText, QString & findText, Qt::CaseSensitivity cs);
 	QString highlightFindText(FindRecord& record);
+#endif
 private:
 	Ui::FindResultWin ui;
 	QMenu *m_menu;
-	QAction* m_pSelectSectonAct;
+	QWidget* m_parent;
 
-	QStandardItemModel* m_model;
-	NdStyledItemDelegate* m_delegate;
+	QList<ResultLineInfo> m_resultLineInfo;
+	QList<QString*> m_resultLineFilePath;
 
-	QWidget* m_parent;
 	int m_defaultFontSize;
 	bool m_defFontSizeChange;
 };

+ 8 - 25
src/findresultwin.ui

@@ -39,31 +39,13 @@
     <number>0</number>
    </property>
    <item row="0" column="0">
-    <widget class="MyTreeView" name="resultTreeView">
-     <property name="font">
-      <font>
-       <family>Microsoft YaHei</family>
-       <pointsize>10</pointsize>
-      </font>
-     </property>
+    <widget class="FindResultView" name="displayView">
      <property name="frameShape">
-      <enum>QFrame::Panel</enum>
-     </property>
-     <property name="lineWidth">
-      <number>1</number>
-     </property>
-     <property name="horizontalScrollBarPolicy">
-      <enum>Qt::ScrollBarAsNeeded</enum>
-     </property>
-     <property name="editTriggers">
-      <set>QAbstractItemView::DoubleClicked</set>
+      <enum>QFrame::StyledPanel</enum>
      </property>
-     <property name="animated">
-      <bool>true</bool>
+     <property name="frameShadow">
+      <enum>QFrame::Raised</enum>
      </property>
-     <attribute name="headerVisible">
-      <bool>true</bool>
-     </attribute>
     </widget>
    </item>
   </layout>
@@ -71,9 +53,10 @@
  <layoutdefault spacing="6" margin="11"/>
  <customwidgets>
   <customwidget>
-   <class>MyTreeView</class>
-   <extends>QTreeView</extends>
-   <header>mytreeview.h</header>
+   <class>FindResultView</class>
+   <extends>QFrame</extends>
+   <header location="global">findresultview.h</header>
+   <container>1</container>
   </customwidget>
  </customwidgets>
  <resources/>

+ 233 - 55
src/findwin.cpp

@@ -5,6 +5,7 @@
 #include "doctypelistview.h"
 #include "filemanager.h"
 #include "ccnotepad.h"
+#include "nddsetting.h"
 
 #include <QMimeDatabase>
 #include <QRadioButton>
@@ -78,7 +79,7 @@ FindWin::~FindWin()
 	{
 		delete pEditTemp;
 		pEditTemp = nullptr;
-}
+	}
 }
 
 void FindWin::slot_tabIndexChange(int index)
@@ -277,6 +278,20 @@ void FindWin::setFindHistory(QList<QString>* findHistory)
 	}
 }
 
+void FindWin::setReplaceHistory(QList<QString>* replaceHistory)
+{
+	m_replaceHistory = replaceHistory;
+
+	if ((m_replaceHistory != nullptr) && !m_replaceHistory->isEmpty())
+	{
+		ui.replaceWithBox->addItems(*m_replaceHistory);
+		ui.replaceWithBox->clearEditText();
+		ui.dirReplaceWhat->addItems(*m_replaceHistory);
+		ui.dirReplaceWhat->clearEditText();
+		
+	}
+}
+
 //标记高亮所有word单词
 int FindWin::markAllWord(QString & word)
 {
@@ -312,7 +327,7 @@ void FindWin::removeLineHeadEndBlank(int mode)
 		{
 			ui.replaceTextBox->setCurrentText("[	 ]+$");
 		}
-		ui.replaceWithBox->setText("");
+		ui.replaceWithBox->setEditText("");
 		
 		ui.replaceModeRegularBt->setChecked(true);
 
@@ -466,9 +481,9 @@ void FindWin::updateParameterFromUI()
 			m_isFindFirst = true;
 		}
 
-		if (m_replaceWithText != ui.replaceWithBox->text())
+		if (m_replaceWithText != ui.replaceWithBox->currentText())
 		{
-			m_replaceWithText = ui.replaceWithBox->text();
+			m_replaceWithText = ui.replaceWithBox->currentText();
 			m_isFindFirst = true;
 		}
 
@@ -528,9 +543,9 @@ void FindWin::updateParameterFromUI()
 			m_isFindFirst = true;
 		}
 
-		if (m_replaceWithText != ui.dirReplaceWhat->text())
+		if (m_replaceWithText != ui.dirReplaceWhat->currentText())
 		{
-			m_replaceWithText = ui.dirReplaceWhat->text();
+			m_replaceWithText = ui.dirReplaceWhat->currentText();
 			m_isFindFirst = true;
 		}
 
@@ -703,6 +718,55 @@ void FindWin::addFindHistory(QString &text)
 	}
 }
 
+void FindWin::addReplaceHistory(QString& text)
+{
+	//太长会导致看起来很杂乱,也不记录
+	if (text.isEmpty() || text.size() >= MAX_RECORD_KEY_LENGTH)
+	{
+		return;
+	}
+
+	if (m_replaceHistory != nullptr)
+	{
+		int index = m_replaceHistory->indexOf(text, 0);
+		//已经是最上面一个了,直接返回
+		if (0 == index)
+		{
+			return;
+		}
+		//没有直接添加到最前面。不做查找删除重复,一是慢,而是删除会引起信号逻辑时序有误
+		if (-1 == index)
+		{
+			m_replaceHistory->push_front(text);
+			ui.replaceWithBox->insertItem(0, text); 
+			ui.dirReplaceWhat->insertItem(0, text);
+		}
+		else
+		{
+			//有了怎么办,删除旧的,加新的
+			m_replaceHistory->removeAt(index);
+			m_replaceHistory->push_front(text);
+
+			//发现不能只删除旧的,有bug,一旦删除后,查找框乱了,被切换到下一个。
+			ui.replaceWithBox->removeItem(index);
+			ui.dirReplaceWhat->removeItem(index);
+			ui.replaceWithBox->insertItem(0, text);
+			ui.dirReplaceWhat->insertItem(0, text);
+			//发现不能只删除旧的,有bug,一旦删除后,查找框乱了,被切换到下一个。
+			//必须重新设置一下,否则查找框里面字段乱跳到下一个去了
+			ui.replaceWithBox->setCurrentIndex(0);
+			ui.dirReplaceWhat->setCurrentIndex(0);
+		}
+
+
+
+		if (m_replaceHistory->size() >= 15)
+		{
+			m_replaceHistory->takeLast();
+		}
+	}
+}
+
 //检查是否是第一次查找,凡是参数变化了,则认定为是第一次查找。
 //因为查找分firstFirst和firstNext,则是qscint特性决定的。所以正确识别第一次查找是必要的
 bool FindWin::isFirstFind()
@@ -876,7 +940,7 @@ void FindWin::removeEmptyLine(bool isBlankContained)
 		{
 			ui.replaceTextBox->setCurrentText("^$(\\r\\n|\\r|\\n)");
 		}
-		ui.replaceWithBox->setText("");
+		ui.replaceWithBox->setEditText("");
 
 		ui.replaceModeRegularBt->setChecked(true);
 
@@ -969,8 +1033,6 @@ void FindWin::dofindNext()
 	updateParameterFromUI();
 
 	QWidget* pw = autoAdjustCurrentEditWin();
-
-
 	QsciScintilla* pEdit = dynamic_cast<QsciScintilla*>(pw);
 
 	//第一次查找
@@ -1095,7 +1157,7 @@ void FindWin::slot_findCount()
 		//这里的forward一定要是true。回环一定是false
 		if (!pEdit->findFirst(whatFind, m_re, m_cs, m_wo, false, true, FINDNEXTTYPE_FINDNEXT, 0, 0,false))
 		{
-			ui.statusbar->showMessage(tr("count %1 times with \'%2\'").arg(countNums).arg(m_expr), 8000);
+			ui.statusbar->showMessage(tr("count %1 times with \'%2\'").arg(countNums).arg(m_expr));
 			QApplication::beep();
 
 			m_isFindFirst = true;
@@ -1119,11 +1181,11 @@ void FindWin::slot_findCount()
 
 		pEdit->execute(SCI_GOTOPOS, srcPostion);
 		pEdit->execute(SCI_SETFIRSTVISIBLELINE, firstDisLineNum);
-		pEdit->execute(SCI_SETXOFFSET, 0);
+		//pEdit->execute(SCI_SETXOFFSET, 0);
 
 		//全部替换后,下次查找,必须算第一次查找
 		m_isFindFirst = true;
-		ui.statusbar->showMessage(tr("count %1 times with \'%2\'").arg(countNums).arg(m_expr), 8000);
+		ui.statusbar->showMessage(tr("count %1 times with \'%2\'").arg(countNums).arg(m_expr));
 	}
 	else
 	{
@@ -1165,11 +1227,16 @@ QString FindWin::addCurFindRecord(ScintillaEditView* pEdit, FindRecords& recordR
 	FindState& state = pEdit->getLastFindState();
 	aRecord.pos = state.targstart;
 	aRecord.end = state.targend;
+	aRecord.lineNum = state.linenum;
 
 	//mark模式不需要这么多信息,可直接返回
 	if (!isMark)
 	{
-		aRecord.lineNum = pEdit->execute(SCI_LINEFROMPOSITION, aRecord.pos);
+		//静默查找,在后台批量查找时,不会返回这个state.linenum。需要手动获取一下
+		if (aRecord.lineNum == -1)
+		{
+			aRecord.lineNum = pEdit->execute(SCI_LINEFROMPOSITION, aRecord.pos);
+		}
 		aRecord.lineStartPos = pEdit->execute(SCI_POSITIONFROMLINE, aRecord.lineNum);
 		int lineLens = pEdit->execute(SCI_LINELENGTH, aRecord.lineNum);
 
@@ -1553,8 +1620,8 @@ int FindWin::findAllInCurDoc(QStringList* reResult)
 
 			if (!m_isStatic)
 			{
-			QApplication::beep();
-			emit sign_findAllInCurDoc(&results);
+				QApplication::beep();
+				emit sign_findAllInCurDoc(&results);
 			}
 
 			m_isFindFirst = true;
@@ -1604,7 +1671,7 @@ int FindWin::findAllInCurDoc(QStringList* reResult)
 
 		pEdit->execute(SCI_GOTOPOS, srcPostion);
 		pEdit->execute(SCI_SETFIRSTVISIBLELINE, firstDisLineNum);
-		pEdit->execute(SCI_SETXOFFSET, 0);
+		//pEdit->execute(SCI_SETXOFFSET, 0);
 
 		//全部替换后,下次查找,必须算第一次查找
 		m_isFindFirst = true;
@@ -1637,11 +1704,110 @@ int FindWin::findAllInCurDoc(QStringList* reResult)
 
 void FindWin::slot_findAllInCurDoc()
 {
-	findAllInCurDoc();
+	//findAllInCurDoc();
+
+	int index = m_editTabWidget->currentIndex();
+
+	if (index >= 0)
+	{
+		findAllInOpenDoc(index);
+	}
+}
+
+void FindWin::findAllInOpenDoc(int index)
+{
+	if (ui.findComboBox->currentText().isEmpty())
+	{
+		ui.statusbar->showMessage(tr("what find is null !"), 8000);
+		QApplication::beep();
+		return;
+	}
+
+	QString whatFind = ui.findComboBox->currentText();
+	QString originWhatFine = whatFind;
+
+	if (m_extend)
+	{
+		QString extendFind;
+		convertExtendedToString(whatFind, extendFind);
+		whatFind = extendFind;
+	}
+
+	int replaceNums = 0;
+	QVector<FindRecords*>* allOpenFileRecord = new QVector<FindRecords*>();
+
+	for (int i = 0; i < m_editTabWidget->count(); ++i)
+	{
+		//是否只查找一个文档
+		if ((index != -1) && (i != index))
+		{
+			continue;
+		}
+		QWidget* pw = m_editTabWidget->widget(i);
+		ScintillaEditView* pEdit = dynamic_cast<ScintillaEditView*>(pw);
+		if (pEdit != nullptr)
+		{
+			if (pEdit->isReadOnly())
+			{
+				continue;
+			}
+
+			FindRecords* results = new FindRecords();
+			results->pEdit = pEdit;
+
+			results->findFilePath = pw->property("filePath").toString();
+
+			updateParameterFromUI();
+
+			//无条件进行第一次查找,从0行0列开始查找,而且不回环。如果没有找到,则替换完毕
+			//results->findText要是有原来的值,因为扩展模式下\r\n不会转义,直接输出会换行显示
+			results->findText = originWhatFine;
+			if (!pEdit->findFirst(whatFind, m_re, m_cs, m_wo, false, true, FINDNEXTTYPE_FINDNEXT, 0, 0))
+			{
+				delete results;
+				continue;
+			}
+			else
+			{
+				dealWithZeroFound(pEdit);
+			}
+			addCurFindRecord(pEdit, *results);
+
+			++replaceNums;
+
+			//找到了,把结果收集起来
+			while (pEdit->findNext())
+			{
+				addCurFindRecord(pEdit, *results);
+				++replaceNums;
+				dealWithZeroFound(pEdit);
+			}
+
+			allOpenFileRecord->append(results);
+		}
+	}
+
+	//全部替换后,下次查找,必须算第一次查找
+	m_isFindFirst = true;
+	ui.statusbar->showMessage(tr("find finished, total %1 found!").arg(replaceNums), 10000);
+
+	emit sign_findAllInOpenDoc(allOpenFileRecord, replaceNums, whatFind);
+
+	//释放元素
+	for (int i = 0; i < allOpenFileRecord->size(); ++i)
+	{
+		delete allOpenFileRecord->at(i);
+	}
+
+	delete allOpenFileRecord;
+
 }
 
 void FindWin::slot_findAllInOpenDoc()
 {
+	findAllInOpenDoc(-1);
+
+#if 0
 	if (ui.findComboBox->currentText().isEmpty())
 	{
 		ui.statusbar->showMessage(tr("what find is null !"), 8000);
@@ -1721,7 +1887,7 @@ void FindWin::slot_findAllInOpenDoc()
 	}
 
 	delete allOpenFileRecord;
-	
+#endif
 }
 
 //返回是否查找得到内容
@@ -1739,6 +1905,9 @@ bool FindWin::replaceFindNext(QsciScintilla* pEdit, bool showZeroFindTip)
 
 			addFindHistory(whatFind);
 
+			QString replaceWith = ui.replaceWithBox->currentText();
+			addReplaceHistory(replaceWith);
+
 			if (m_extend)
 			{
 				QString extendFind;
@@ -1815,7 +1984,7 @@ bool FindWin::replace(ScintillaEditView* pEdit)
 	}
 
 	QString findText = ui.replaceTextBox->currentText();
-	QString replaceText = ui.replaceWithBox->text();
+	QString replaceText = ui.replaceWithBox->currentText();
 
 	if (m_extend)
 	{
@@ -2078,7 +2247,7 @@ int FindWin::doReplaceAll(ScintillaEditView* pEdit, QString &whatFind, QString&
 
 	if (isCombineUndo)
 	{
-	pEdit->execute(SCI_BEGINUNDOACTION);
+		pEdit->execute(SCI_BEGINUNDOACTION);
 	}
 
 	int flags = buildSearchFlags(m_re, m_cs, m_wo, false, true, FINDNEXTTYPE_REPLACENEXT, 0, 0);
@@ -2142,14 +2311,12 @@ int FindWin::doReplaceAll(ScintillaEditView* pEdit, QString &whatFind, QString&
 
 	if (isCombineUndo)
 	{
-	pEdit->execute(SCI_ENDUNDOACTION);
+		pEdit->execute(SCI_ENDUNDOACTION);
 	}
 
 	pEdit->execute(SCI_GOTOPOS, srcPostion);
 	pEdit->execute(SCI_SETFIRSTVISIBLELINE, firstDisLineNum);
-	pEdit->execute(SCI_SETXOFFSET, 0);
-
-	
+	//pEdit->execute(SCI_SETXOFFSET, 0);
 
 	return replaceNums;
 }
@@ -2181,7 +2348,7 @@ int FindWin::replaceAll()
 	updateParameterFromUI();
 
 	QString whatFind = ui.replaceTextBox->currentText();
-	QString replaceText = ui.replaceWithBox->text();
+	QString replaceText = ui.replaceWithBox->currentText();
 
 	if (m_extend)
 	{
@@ -2285,7 +2452,7 @@ void FindWin::slot_replaceAllInOpenDoc()
 	ui.statusbar->showMessage(tr("Replace in Opened Files: %1 occurrences were replaced.").arg(replaceNums), 10000);
 }
 
-int  FindWin::markAll()
+int  FindWin::markAll(QSet<int>* outLineNum)
 {
 	if (ui.markTextBox->currentText().isEmpty())
 	{
@@ -2362,6 +2529,11 @@ int  FindWin::markAll()
 				pEdit->execute(SCI_SETINDICATORCURRENT, CCNotePad::s_curMarkColorId);
 				pEdit->execute(SCI_INDICATORFILLRANGE, rs.pos, foundTextLen);
 			}
+
+			if (outLineNum != nullptr)
+			{
+				outLineNum->insert(rs.lineNum);
+			}
 		}
 
 		if (!results->records.isEmpty())
@@ -2369,15 +2541,15 @@ int  FindWin::markAll()
 			pEdit->appendMarkRecord(results);
 		}
 
-
-		pEdit->execute(SCI_SETFIRSTVISIBLELINE, firstDisLineNum);
 		pEdit->execute(SCI_GOTOPOS, srcPostion);
-		pEdit->execute(SCI_SETXOFFSET, 0);
+		pEdit->execute(SCI_SETFIRSTVISIBLELINE, firstDisLineNum);
+		//pEdit->execute(SCI_SETXOFFSET, 0);
 
 		//全部替换后,下次查找,必须算第一次查找
 		m_isFindFirst = true;
 		ui.statusbar->showMessage(tr("mark finished, total %1 found!").arg(replaceNums), 10000);
 
+	
 		return replaceNums;
 	}
 	else
@@ -2426,6 +2598,10 @@ void FindWin::slot_dirSelectDest()
 	QString curDirPath = ui.destFindDir->text();
 	if (curDirPath.isEmpty())
 	{
+		if (CCNotePad::s_lastOpenDirPath.isEmpty())
+		{
+			CCNotePad::s_lastOpenDirPath = NddSetting::getKeyValueFromDelaySets(LAST_OPEN_DIR);
+		}
 		curDirPath = CCNotePad::s_lastOpenDirPath;
 	}
 
@@ -2512,30 +2688,14 @@ bool FindWin::replaceTextInFile(QString &filePath, int &replaceNums, QVector<Fin
 		replace = extendReplace;
 	}
 
-	replaceNums += doReplaceAll(pEditTemp, find, replace);
-
-#if 0
-	if (!pEditTemp->findFirst(find, m_re, m_cs, m_wo, false, m_forward, FINDNEXTTYPE_REPLACENEXT,0, 0,false))
-	{
-		return false;
-	}
-
-	pEditTemp->replace(replace);
-	dealWithZeroFound(pEditTemp);
-
-	++replaceNums;
+	int modifyTimes = doReplaceAll(pEditTemp, find, replace);
 
-	//找到了,则自动进行全部替换
-	while (pEditTemp->findNext())
+	if (modifyTimes > 0)
 	{
-		pEditTemp->replace(replace);
-		++replaceNums;
-		dealWithZeroFound(pEditTemp);
+		replaceNums += modifyTimes;
+		//如果进行过替换,则必须要保存一下;否则不能保存,不然文件被修改。
+		emit sign_replaceSaveFile(filePath, pEditTemp);
 	}
-#endif
-
-	//必须要保存一下
-	emit sign_replaceSaveFile(filePath, pEditTemp);
 
 	return true;
 }
@@ -2848,7 +3008,7 @@ void FindWin::slot_dirFindAll()
 
 	if (pEditTemp == nullptr)
 	{
-		pEditTemp = new ScintillaEditView(nullptr);
+		pEditTemp = ScintillaEditView::createEditForSearch();
 	}
 
 	int foundNums = 0;
@@ -2860,7 +3020,7 @@ void FindWin::slot_dirFindAll()
 
 	//全部替换后,下次查找,必须算第一次查找
 	m_isFindFirst = true;
-	ui.statusbar->showMessage(tr("find finished, total %1 found in %2 file!").arg(foundNums).arg(filesNum), 10000);
+	ui.statusbar->showMessage(tr("find finished, walk %1 files, total %2 found in %3 file!").arg(filesNum).arg(foundNums).arg(allfileInDirRecord->size()));
 
 	//复用了这个信号函数,没有新做消息,要注意
 	emit sign_findAllInOpenDoc(allfileInDirRecord, foundNums, whatFind);
@@ -2882,7 +3042,7 @@ void FindWin::slot_dirReplaceAll()
 {
 	QString dirPath = ui.destFindDir->text();
 	QString whatFind = ui.dirFindWhat->currentText();
-	QString dirReplaceWhat = ui.dirReplaceWhat->text();
+	QString dirReplaceWhat = ui.dirReplaceWhat->currentText();
 
 	if (dirPath.isEmpty())
 	{
@@ -2964,12 +3124,15 @@ void FindWin::slot_dirReplaceAll()
 	int skipMaxSize = (ui.skipFileMaxSize->isChecked()) ? ui.maxFileSizeSpinBox->value() * 1024 * 1024 : 0;
 	bool isSkipChildDir = ui.skipChildDirs->isChecked();
 
+	addReplaceHistory(dirReplaceWhat);
+
 	updateParameterFromUI();
 
 	if (pEditTemp == nullptr)
 	{
-		pEditTemp = new ScintillaEditView(nullptr);
+		pEditTemp = ScintillaEditView::createEditForSearch();
 	}
+
 	int replaceNums = 0;
 
 	std::function<bool(QString &, int &, QVector<FindRecords*>* allfileInDirRecord)> foundCallBack = std::bind(&FindWin::replaceTextInFile, this, std::placeholders::_1, std::placeholders::_2, nullptr);
@@ -2978,7 +3141,7 @@ void FindWin::slot_dirReplaceAll()
 
 	//全部替换后,下次查找,必须算第一次查找
 	m_isFindFirst = true;
-	ui.statusbar->showMessage(tr("replace finished, total %1 replace in %2 file!").arg(replaceNums).arg(filesNum), 10000);
+	ui.statusbar->showMessage(tr("replace finished, walk %1 files, total %2 replace !").arg(filesNum).arg(replaceNums));
 }
 
 
@@ -2999,4 +3162,19 @@ void  FindWin::on_copyReFindResult()
 		QClipboard* clipboard = QApplication::clipboard();
 		clipboard->setText(reResult.join("\n"));
 	}
+}
+
+void FindWin::on_markAndBook()
+{
+	QSet<int> outLineNum;
+	markAll(&outLineNum);
+
+	QWidget* pw = autoAdjustCurrentEditWin();
+	ScintillaEditView* pEdit = dynamic_cast<ScintillaEditView*>(pw);
+
+	if (pEdit != nullptr)
+	{
+		pEdit->bookmarkAdd(outLineNum);
+	}
+
 }

+ 9 - 1
src/findwin.h

@@ -69,6 +69,7 @@ public:
 	void setMarkFindText(QString& text);
 	void disableReplace();
 	void setFindHistory(QList<QString>* findHistory);
+	void setReplaceHistory(QList<QString>* replaceHistory);
 	int markAllWord(QString& word);
 	void removeLineHeadEndBlank(int mode);
 	static void showCallTip(QsciScintilla * pEdit, int pos);
@@ -97,6 +98,7 @@ signals:
 private:
 	void updateParameterFromUI();
 	void addFindHistory(QString & text);
+	void addReplaceHistory(QString& text);
 	bool isFirstFind();
 	
 	QString addCurFindRecord(ScintillaEditView * pEdit, FindRecords & recordRet, bool isMark=false, bool getResult=false);
@@ -125,10 +127,12 @@ private:
 
 	int replaceAll();
 
-	int markAll();
+	int markAll(QSet<int>* outLineNum=nullptr);
 
 	int findAllInCurDoc(QStringList * reResult=nullptr);
 
+	void findAllInOpenDoc(int index = -1);
+
 private slots:
 
 	void slot_findNext();
@@ -173,6 +177,8 @@ private slots:
 
 	void on_copyReFindResult();
 
+	void on_markAndBook();
+
 private:
 	Ui::FindWin ui;
 
@@ -216,6 +222,8 @@ private:
 
 	QList<QString>* m_findHistory;
 
+	QList<QString>* m_replaceHistory;
+
 	ScintillaEditView* pEditTemp;
 
 	QWidget* m_curEditWin;

+ 80 - 55
src/findwin.ui

@@ -403,13 +403,7 @@
                </widget>
               </item>
               <item>
-               <widget class="QLineEdit" name="replaceWithBox">
-                <property name="sizePolicy">
-                 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
-                  <horstretch>0</horstretch>
-                  <verstretch>0</verstretch>
-                 </sizepolicy>
-                </property>
+               <widget class="QComboBox" name="replaceWithBox">
                 <property name="minimumSize">
                  <size>
                   <width>300</width>
@@ -422,6 +416,12 @@
                   <height>16777215</height>
                  </size>
                 </property>
+                <property name="editable">
+                 <bool>true</bool>
+                </property>
+                <property name="maxCount">
+                 <number>512</number>
+                </property>
                </widget>
               </item>
              </layout>
@@ -759,8 +759,21 @@
           </item>
           <item>
            <layout class="QGridLayout" name="gridLayout_5">
-            <item row="1" column="1">
-             <widget class="QLineEdit" name="fileType">
+            <item row="1" column="0">
+             <widget class="QLabel" name="label_6">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="text">
+               <string>Replace with :</string>
+              </property>
+             </widget>
+            </item>
+            <item row="3" column="1">
+             <widget class="QLineEdit" name="skipDirNames">
               <property name="enabled">
                <bool>false</bool>
               </property>
@@ -783,37 +796,11 @@
                </size>
               </property>
               <property name="placeholderText">
-               <string>*.c:*.cpp:*.h</string>
-              </property>
-             </widget>
-            </item>
-            <item row="1" column="0">
-             <widget class="QCheckBox" name="dealFileType">
-              <property name="sizePolicy">
-               <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
-                <horstretch>0</horstretch>
-                <verstretch>0</verstretch>
-               </sizepolicy>
-              </property>
-              <property name="text">
-               <string>File Type :</string>
-              </property>
-             </widget>
-            </item>
-            <item row="0" column="0">
-             <widget class="QLabel" name="label_6">
-              <property name="sizePolicy">
-               <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
-                <horstretch>0</horstretch>
-                <verstretch>0</verstretch>
-               </sizepolicy>
-              </property>
-              <property name="text">
-               <string>Replace with :</string>
+               <string>debug:Debug:.vs:.git:.svn</string>
               </property>
              </widget>
             </item>
-            <item row="2" column="0">
+            <item row="3" column="0">
              <widget class="QCheckBox" name="skipDir">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
@@ -827,7 +814,7 @@
              </widget>
             </item>
             <item row="2" column="1">
-             <widget class="QLineEdit" name="skipDirNames">
+             <widget class="QLineEdit" name="fileType">
               <property name="enabled">
                <bool>false</bool>
               </property>
@@ -850,29 +837,33 @@
                </size>
               </property>
               <property name="placeholderText">
-               <string>debug:Debug:.vs:.git:.svn</string>
+               <string>*.c:*.cpp:*.h</string>
               </property>
              </widget>
             </item>
-            <item row="0" column="1">
-             <widget class="QLineEdit" name="dirReplaceWhat">
+            <item row="2" column="0">
+             <widget class="QCheckBox" name="dealFileType">
               <property name="sizePolicy">
-               <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+               <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
                 <horstretch>0</horstretch>
                 <verstretch>0</verstretch>
                </sizepolicy>
               </property>
+              <property name="text">
+               <string>File Type :</string>
+              </property>
+             </widget>
+            </item>
+            <item row="1" column="1">
+             <widget class="QComboBox" name="dirReplaceWhat">
               <property name="minimumSize">
                <size>
                 <width>300</width>
                 <height>0</height>
                </size>
               </property>
-              <property name="maximumSize">
-               <size>
-                <width>350</width>
-                <height>16777215</height>
-               </size>
+              <property name="editable">
+               <bool>true</bool>
               </property>
              </widget>
             </item>
@@ -1312,6 +1303,25 @@
             </property>
            </widget>
           </item>
+          <item>
+           <widget class="QPushButton" name="pushButton">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="minimumSize">
+             <size>
+              <width>200</width>
+              <height>28</height>
+             </size>
+            </property>
+            <property name="text">
+             <string>Mark &amp; Bookmark</string>
+            </property>
+           </widget>
+          </item>
           <item>
            <widget class="QPushButton" name="markClearBox">
             <property name="sizePolicy">
@@ -1410,7 +1420,6 @@
   <tabstop>findModeExtendBt</tabstop>
   <tabstop>findModeRegularBt</tabstop>
   <tabstop>replaceTextBox</tabstop>
-  <tabstop>replaceWithBox</tabstop>
   <tabstop>replaceFindNextBox</tabstop>
   <tabstop>replaceBt</tabstop>
   <tabstop>replaceAllBt</tabstop>
@@ -1425,7 +1434,6 @@
   <tabstop>replaceModeRegularBt</tabstop>
   <tabstop>destFindDir</tabstop>
   <tabstop>dirFindWhat</tabstop>
-  <tabstop>dirReplaceWhat</tabstop>
   <tabstop>selectDir</tabstop>
   <tabstop>dirFindAll</tabstop>
   <tabstop>dirReplaceAll</tabstop>
@@ -1627,8 +1635,8 @@
    <slot>slot_clearMark()</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>489</x>
-     <y>84</y>
+     <x>672</x>
+     <y>129</y>
     </hint>
     <hint type="destinationlabel">
      <x>588</x>
@@ -1643,8 +1651,8 @@
    <slot>close()</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>572</x>
-     <y>162</y>
+     <x>672</x>
+     <y>197</y>
     </hint>
     <hint type="destinationlabel">
      <x>404</x>
@@ -1755,8 +1763,8 @@
    <slot>slot_clearAllMark()</slot>
    <hints>
     <hint type="sourcelabel">
-     <x>538</x>
-     <y>112</y>
+     <x>672</x>
+     <y>163</y>
     </hint>
     <hint type="destinationlabel">
      <x>574</x>
@@ -1780,6 +1788,22 @@
     </hint>
    </hints>
   </connection>
+  <connection>
+   <sender>pushButton</sender>
+   <signal>clicked()</signal>
+   <receiver>FindWin</receiver>
+   <slot>on_markAndBook()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>565</x>
+     <y>77</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>434</x>
+     <y>386</y>
+    </hint>
+   </hints>
+  </connection>
  </connections>
  <slots>
   <slot>slot_findNext()</slot>
@@ -1799,5 +1823,6 @@
   <slot>slot_findPrev()</slot>
   <slot>slot_clearAllMark()</slot>
   <slot>on_copyReFindResult()</slot>
+  <slot>on_markAndBook()</slot>
  </slots>
 </ui>

+ 6 - 2
src/main.cpp

@@ -120,8 +120,12 @@ class MyApplication : public QApplication
 
 int main(int argc, char *argv[])
 {
-	//可以防止某些屏幕下的字体拥挤重叠问题
-	QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+	//可以防止某些屏幕下的字体拥挤重叠问题。暂时屏蔽,不使用qt方法,使用windows自带方案
+	// 发现windows自带方案模糊。//发现下面打开后,在win10上反而效果不好,界面会变得很大,默认还是不开启的好。
+	//QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+	//QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
+	//QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor);
+
 #ifdef Q_OS_MAC
     MyApplication a(argc, argv);
 #else

+ 18 - 0
src/markdownview.cpp

@@ -0,0 +1,18 @@
+#include "markdownview.h"
+
+MarkdownView::MarkdownView(QWidget *parent)
+	: QMainWindow(parent)
+{
+	ui.setupUi(this);
+}
+
+MarkdownView::~MarkdownView()
+{
+
+}
+
+
+void MarkdownView::viewMarkdown(QString& text)
+{
+	ui.textEdit->setMarkdown(text);
+}

+ 17 - 0
src/markdownview.h

@@ -0,0 +1,17 @@
+#pragma once
+
+#include <QMainWindow>
+#include "ui_markdownview.h"
+
+class MarkdownView : public QMainWindow
+{
+	Q_OBJECT
+
+public:
+	MarkdownView(QWidget *parent = nullptr);
+	~MarkdownView();
+	void viewMarkdown(QString& text);
+
+private:
+	Ui::MarkdownViewClass ui;
+};

+ 65 - 0
src/markdownview.ui

@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MarkdownViewClass</class>
+ <widget class="QMainWindow" name="MarkdownViewClass">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1134</width>
+    <height>712</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>MarkdownView</string>
+  </property>
+  <widget class="QWidget" name="centralWidget">
+   <layout class="QVBoxLayout" name="verticalLayout">
+    <property name="spacing">
+     <number>3</number>
+    </property>
+    <property name="leftMargin">
+     <number>3</number>
+    </property>
+    <property name="topMargin">
+     <number>3</number>
+    </property>
+    <property name="rightMargin">
+     <number>3</number>
+    </property>
+    <property name="bottomMargin">
+     <number>3</number>
+    </property>
+    <item>
+     <widget class="QTextEdit" name="textEdit">
+      <property name="readOnly">
+       <bool>true</bool>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menuBar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>1134</width>
+     <height>23</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QToolBar" name="mainToolBar">
+   <attribute name="toolBarArea">
+    <enum>TopToolBarArea</enum>
+   </attribute>
+   <attribute name="toolBarBreak">
+    <bool>false</bool>
+   </attribute>
+  </widget>
+  <widget class="QStatusBar" name="statusBar"/>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections/>
+</ui>

+ 25 - 0
src/nddpluginapi.cpp

@@ -0,0 +1,25 @@
+#include "nddpluginapi.h"
+#include "ccnotepad.h"
+
+NddPluginApi::NddPluginApi(QObject *parent)
+	: QObject(parent)
+{}
+
+NddPluginApi::~NddPluginApi()
+{}
+
+void NddPluginApi::setMainNotePad(QWidget * pWidget)
+{
+	m_mainNotePad = pWidget;
+}
+
+//×¢ÒâÕâÀïʵ¼Ê·µ»ØµÄÊÇScintillaEditView
+QsciScintilla* NddPluginApi::getCurrentEidtHandle()
+{
+	CCNotePad* pNotepad = dynamic_cast<CCNotePad*>(m_mainNotePad);
+	if (pNotepad != nullptr)
+	{
+		return pNotepad->getCurEditView();
+	}
+	return nullptr;
+}

+ 37 - 0
src/nddpluginapi.h

@@ -0,0 +1,37 @@
+#pragma once
+
+#include <QObject>
+#include <QMap>
+#include <QVariant>
+
+//这个类供插件中调用,务必要保证该类的ABI兼容性。
+//这意味着,不能随意增加删除该类中的函数和成员变量;否则会导致插件无法兼容。
+//不使用除虚函数之外的任何虚函数
+//理论上最好一个插件,对应一个该对象。这样不会冲突。
+
+class QsciScintilla;
+
+class NddPluginApi  : public QObject
+{
+	Q_OBJECT
+
+public:
+	NddPluginApi(QObject *parent);
+	~NddPluginApi();
+
+	//获取当前编辑框的对象这个一定要每次动态获取。这里也有问题,一旦QsciScintilla修改,还是不能起到ABI兼容。
+	//尽量依赖不需要改动的部分。
+
+	void setMainNotePad(QWidget* pWidget);
+
+	//有了这个当前编辑框后,就可以动态做许多事情了。但是前提是QsciScintilla基类不能随意修改。
+	QsciScintilla* getCurrentEidtHandle();
+
+
+
+	//这个里面的成员函数要特别小心,一旦给定,则顺序和参数不能随意修改。只能依次往后增加、不能删除。
+public:
+	//使用动态参数进行参数的传递。使用public传递成员参数
+	QMap<QString, QVariant> m_parameter;
+	QWidget* m_mainNotePad;
+};

+ 17 - 2
src/nddsetting.cpp

@@ -88,10 +88,10 @@ void NddSetting::init()
 		//开启自动缩进
 		addKeyValueToNumSets(INDENT_KEY, 0);
 
-		//显示空白
+		//显示空白。0都不显示 1 单显示空格 2 单显示行尾 3 都显示
 		addKeyValueToNumSets(SHOWSPACE_KEY, 0);
 
-		//最大文本文件的门限。默认100M.(50-300)
+		//最大文本文件的门限。默认100M.(50-600)
 		addKeyValueToNumSets(MAX_BIG_TEXT, 100);
 
 		addKeyValueToSets(SOFT_KEY, "0");
@@ -364,3 +364,18 @@ bool NddSetting::updataKeyValueFromDelaySets(QString key, QString value)
 	s_isContentChanged = true;
 	return true;
 }
+
+//写一个总的获取配置的接口,避免以后每个字段都需要写一个读写接口
+int NddSetting::getKeyValueFromDelayNumSets(QString key)
+{
+	nddDelaySetInit();
+	return s_nddDelaySet->value(key, "").toInt();
+}
+
+bool NddSetting::updataKeyValueFromDelayNumSets(QString key, int value)
+{
+	nddDelaySetInit();
+	s_nddDelaySet->setValue(key, value);
+	s_isContentChanged = true;
+	return true;
+}

+ 6 - 0
src/nddsetting.h

@@ -27,6 +27,8 @@ static QString FIND_RESULT_FONT_SIZE = "frfs";//查找结果的默认字体大
 static QString LAST_ACTION_TAB_INDEX = "lati";//上次关闭时,当前激活的tab标签页序号
 
 static QString RECENT_OPEN_FILE = "recentopenfile";
+static QString LAST_OPEN_DIR = "lastdir";
+static QString CLEAR_OPENFILE_ON_CLOSE = "clearopenfile"; //关闭时清空历史文件
 
 
 //下面这个是winpos.ini中的key,避免单个文件太大,拖慢启动速度
@@ -65,6 +67,10 @@ public:
 
 	static bool updataKeyValueFromDelaySets(QString key, QString  value);
 
+	static int getKeyValueFromDelayNumSets(QString key);
+
+	static bool updataKeyValueFromDelayNumSets(QString key, int value);
+
 	static bool isDbExist()
 	{
 		return s_isExistDb;

+ 0 - 62
src/ndstyleditemdelegate.cpp

@@ -1,62 +0,0 @@
-#include "ndstyleditemdelegate.h"
-#include <QTextDocument>
-#include <QApplication>
-#include <QAbstractTextDocumentLayout>
-#include <QPainter>
-#include <QTextEdit>
-
-NdStyledItemDelegate::NdStyledItemDelegate(QObject *parent)
-	: QStyledItemDelegate(parent), m_defaultFontSize(14)
-{
-}
-
-NdStyledItemDelegate::~NdStyledItemDelegate()
-{
-}
-
-
-void NdStyledItemDelegate::setFontSize(int size)
-{
-	m_defaultFontSize = size;
-	
-}
-
-//重载使可以支持富文本格式的文字
-void NdStyledItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
-{
-	QStyleOptionViewItem viewOption(option);
-	initStyleOption(&viewOption, index);
-	if (option.state.testFlag(QStyle::State_HasFocus))
-		viewOption.state = viewOption.state ^ QStyle::State_HasFocus;
-
-	// ... 省略
-	// 设置显示文本为空,使用默认样式
-	QStyle *pStyle = viewOption.widget ? viewOption.widget->style() : QApplication::style();
-
-	QTextDocument doc;
-
-	//外部修改了字体大小后,内部进行富文本的修改绘制。
-	if (m_defaultFontSize != 14)
-	{
-		viewOption.text.replace("font-size:14px",QString("font-size:%1px").arg(m_defaultFontSize));
-	}
-
-	doc.setHtml(viewOption.text);
-
-	viewOption.text.clear();
-
-	pStyle->drawControl(QStyle::CE_ItemViewItem, &viewOption, painter, viewOption.widget);
-
-	QAbstractTextDocumentLayout::PaintContext paintContext;
-
-	QRect textRect = pStyle->subElementRect(QStyle::SE_ItemViewItemText, &viewOption);
-	painter->save();
-	// 坐标变换,将左上角设置为原点
-	painter->translate(textRect.topLeft());
-	// 设置HTML绘制区域
-	painter->setClipRect(textRect.translated(-textRect.topLeft()));
-
-	doc.documentLayout()->draw(painter, paintContext);
-
-	painter->restore();
-}

+ 1 - 1
src/plugin.h

@@ -5,6 +5,6 @@ class QMenu;
 class QsciScintilla;
 class QWidget;
 
-typedef int (*NDD_PROC_MAIN_CALLBACK)(QWidget* parent, const QString& strFileName, std::function<QsciScintilla*()>getCurEdit, NDD_PROC_DATA* procData);
+typedef int (*NDD_PROC_MAIN_CALLBACK)(QWidget* parent, const QString& strFileName, std::function<QsciScintilla*()>getCurEdit, std::function<bool(int, void*)>, NDD_PROC_DATA* procData);
 
 int loadProc(const QString& strDirOut, std::function<void(NDD_PROC_DATA&, QMenu*)> funcallback, QMenu* pUserData);

+ 1 - 1
src/plugin/helloworld/helloworld.pro

@@ -1,7 +1,7 @@
 TEMPLATE	= lib
 LANGUAGE	= C++
 
-CONFIG	+= qt warn_on
+CONFIG	+= qt warn_on Release
 QT += core gui widgets
 
 HEADERS	+= *.h

+ 32 - 3
src/plugin/helloworld/helloworldexport.cpp

@@ -4,6 +4,9 @@
 #include <functional>
 #include <qsciscintilla.h>
 #include "qttestclass.h"
+#ifdef WIN32
+#include <Windows.h>
+#endif
 
 #define NDD_EXPORTDLL
 
@@ -22,7 +25,7 @@
 #endif
 
 	NDD_EXPORT bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData);
-	NDD_EXPORT int NDD_PROC_MAIN(QWidget* pNotepad, const QString& strFileName, std::function<QsciScintilla* ()>getCurEdit, NDD_PROC_DATA* procData);
+	NDD_EXPORT int NDD_PROC_MAIN(QWidget* pNotepad, const QString& strFileName, std::function<QsciScintilla* ()>getCurEdit, std::function<bool(int, void*)> pluginCallBack, NDD_PROC_DATA* procData);
 
 
 #ifdef __cplusplus
@@ -32,6 +35,7 @@
 static NDD_PROC_DATA s_procData;
 static QWidget* s_pMainNotepad = nullptr;
 std::function<QsciScintilla* ()> s_getCurEdit;
+std::function<bool(int, void*)> s_invokeMainFun;
 
 bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData)
 {
@@ -40,7 +44,7 @@ bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData)
 		return false;
 	}
 	pProcData->m_strPlugName = QObject::tr("Hello World Plug");
-	pProcData->m_strComment = QObject::tr("char to Upper.");
+	pProcData->m_strComment = QObject::tr(u8"不需要创建二级菜单的插件例子");
 
 	pProcData->m_version = QString("v1.0");
 	pProcData->m_auther = QString("zuowei.yin");
@@ -54,9 +58,10 @@ bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData)
 //pNotepad:就是CCNotepad的主界面指针
 //strFileName:当前插件DLL的全路径,如果不关心,则可以不使用
 //getCurEdit:从NDD主程序传递过来的仿函数,通过该函数获取当前编辑框操作对象QsciScintilla
+//s_invokeMainFun: 可以回调NDD主程序中的功能函数,比如创建新文件功能等,根据需要可实时扩展。
 //pProcData:如果pProcData->m_menuType = 0 ,则该指针为空;如果pProcData->m_menuType = 1,则该指针有值。目前需要关心s_procData.m_rootMenu
 //开发者可以在该菜单下面,自行创建二级菜单
-int NDD_PROC_MAIN(QWidget* pNotepad, const QString &strFileName, std::function<QsciScintilla*()>getCurEdit, NDD_PROC_DATA* pProcData)
+int NDD_PROC_MAIN(QWidget* pNotepad, const QString &strFileName, std::function<QsciScintilla*()>getCurEdit, std::function<bool(int, void*)> pluginCallBack, NDD_PROC_DATA* pProcData)
 {
 	QsciScintilla* pEdit = getCurEdit();
 	if (pEdit == nullptr)
@@ -72,6 +77,7 @@ int NDD_PROC_MAIN(QWidget* pNotepad, const QString &strFileName, std::function<Q
 
 	s_pMainNotepad = pNotepad;
 	s_getCurEdit = getCurEdit;
+	s_invokeMainFun = pluginCallBack;
 
 	//如果pProcData->m_menuType = 1;是自己要创建二级菜单的场景。则通过s_procData.m_rootMenu 获取该插件的菜单根节点。
 	//插件开发者自行在s_procData.m_rootMenu下添加新的二级菜单项目
@@ -85,3 +91,26 @@ int NDD_PROC_MAIN(QWidget* pNotepad, const QString &strFileName, std::function<Q
 
 	return 0;
 }
+
+#ifdef WIN32
+BOOL WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, LPVOID lpvReserved) {
+	switch (fdwReason) {
+	case DLL_PROCESS_ATTACH:
+	case DLL_THREAD_ATTACH:
+		break;
+	case DLL_THREAD_DETACH:
+		break;
+	case DLL_PROCESS_DETACH:
+		if (NULL == lpvReserved) {
+			//做全局回收工作
+		}
+		break;
+	}
+	return TRUE;
+}
+#else
+void onDllUnload(void)
+{
+	//做全局回收工作
+}
+#endif

+ 10 - 5
src/plugin/test/test.cpp

@@ -4,6 +4,9 @@
 #include <functional>
 #include <qsciscintilla.h>
 #include <QAction>
+#ifdef WIN32
+#include <Windows.h>
+#endif
 
 #define NDD_EXPORTDLL
 
@@ -22,7 +25,7 @@
 #endif
 
 	NDD_EXPORT bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData);
-	NDD_EXPORT int NDD_PROC_MAIN(QWidget* pNotepad, const QString& strFileName, std::function<QsciScintilla* ()>getCurEdit, NDD_PROC_DATA* procData);
+	NDD_EXPORT int NDD_PROC_MAIN(QWidget* pNotepad, const QString& strFileName, std::function<QsciScintilla* ()>getCurEdit, std::function<bool(int, void*)> pluginCallBack, NDD_PROC_DATA* procData);
 
 #ifdef __cplusplus
 	}
@@ -31,6 +34,7 @@
 static NDD_PROC_DATA s_procData;
 static QWidget* s_pMainNotepad = nullptr;
 std::function<QsciScintilla* ()> s_getCurEdit;
+std::function<bool(int, void*)> s_invokeMainFun;
 
 bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData)
 {
@@ -38,8 +42,8 @@ bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData)
 	{
 		return false;
 	}
-	pProcData->m_strPlugName = QObject::tr("Test Plug");
-	pProcData->m_strComment = QObject::tr("char to lower.");
+	pProcData->m_strPlugName = QObject::tr("Create Second Menu Plug");
+	pProcData->m_strComment = QObject::tr(u8"创建二级菜单的插件例子");
 
 	pProcData->m_version = QString("v1.0");
 	pProcData->m_auther = QString("zuowei.yin");
@@ -53,8 +57,9 @@ bool NDD_PROC_IDENTIFY(NDD_PROC_DATA* pProcData)
 //strFileName:当前插件DLL的全路径,如果不关心,则可以不使用
 //getCurEdit:从NDD主程序传递过来的仿函数,通过该函数获取当前编辑框操作对象QsciScintilla
 //pProcData:如果pProcData->m_menuType = 0 ,则该指针为空;如果pProcData->m_menuType = 1,则该指针有值。目前需要关心s_procData.m_rootMenu
-//开发者可以在该菜单下面,自行创建二级菜单
-int NDD_PROC_MAIN(QWidget* pNotepad, const QString& strFileName, std::function<QsciScintilla* ()>getCurEdit, NDD_PROC_DATA* pProcData)
+//s_invokeMainFun: 可以回调NDD主程序中的功能函数,比如创建新文件功能等,根据需要可实时扩展。
+//开发者可以在该菜单下面,自行创建二级菜单.更详细的例子,请见jstool min插件。
+int NDD_PROC_MAIN(QWidget* pNotepad, const QString& strFileName, std::function<QsciScintilla* ()>getCurEdit, std::function<bool(int, void*)> pluginCallBack, NDD_PROC_DATA* pProcData)
 {
 
 	//务必拷贝一份pProcData,在外面会释放。

+ 7 - 1
src/qscint/scintilla/src/EditView.cpp

@@ -833,7 +833,13 @@ static void DrawTextBlob(Surface *surface, const ViewStyle &vsDraw, PRectangle r
 	PRectangle rcChar = rcCChar;
 	rcChar.left++;
 	rcChar.right--;
-	surface->DrawTextClipped(rcChar, ctrlCharsFont,
+	// In the original Scintilla code this was a call to DrawTextClipped().
+	// This caused the clipping to be incorrect (triggered when EOLs are
+	// visible) causing text to overwrite the margins when scrolling.  The
+	// change is consistent with the alternative code paths to where
+	// DrawTextBlob() is called bu tthe root cause maybe in PlatQt.cpp or in Qt
+	// itself.
+	surface->DrawTextNoClip(rcChar, ctrlCharsFont,
 		rcSegment.top + vsDraw.maxAscent, s, static_cast<int>(s ? strlen(s) : 0),
 		textBack, textFore);
 }

+ 1 - 1
src/qscint/scintilla/src/Editor.cpp

@@ -5622,7 +5622,7 @@ void Editor::StyleSetMessage(unsigned int iMessage, uptr_t wParam, sptr_t lParam
 		vs.styles[wParam].back = ColourDesired(static_cast<int>(lParam));
 		break;
 	case SCI_STYLESETBOLD:
-		vs.styles[wParam].weight = lParam != 0 ? SC_WEIGHT_BOLD : SC_WEIGHT_NORMAL;
+		vs.styles[wParam].weight = ((lParam != 0) ? SC_WEIGHT_BOLD : SC_WEIGHT_NORMAL);
 		break;
 	case SCI_STYLESETWEIGHT:
 		vs.styles[wParam].weight = static_cast<int>(lParam);

+ 11 - 11
src/qscint/src/InputMethod.cpp

@@ -1,4 +1,4 @@
-// Copyright (c) 2021 Riverbank Computing Limited
+// Copyright (c) 2023 Riverbank Computing Limited
 // Copyright (c) 2011 Archaeopteryx Software, Inc.
 // Copyright (c) 1990-2011, Scientific Toolworks, Inc.
 //
@@ -137,44 +137,45 @@ void QsciScintillaBase::inputMethodEvent(QInputMethodEvent *event)
         return;
     }
 
+    bool initialCompose = false;
     if (sci->pdoc->TentativeActive()) {
         sci->pdoc->TentativeUndo();
     } else {
         // No tentative undo means start of this composition so
         // Fill in any virtual spaces.
-        sci->ClearBeforeTentativeStart();
+        initialCompose = true;
     }
 
     sci->view.imeCaretBlockOverride = false;
 
     if (!event->commitString().isEmpty()) {
         const QString commitStr = event->commitString();
-        const unsigned int commitStrLen = commitStr.length();
+        const int commitStrLen = commitStr.length();
 
-        for (unsigned int i = 0; i < commitStrLen;) {
-            const unsigned int ucWidth = commitStr.at(i).isHighSurrogate() ? 2 : 1;
+        for (int i = 0; i < commitStrLen;) {
+            const int ucWidth = commitStr.at(i).isHighSurrogate() ? 2 : 1;
             const QString oneCharUTF16 = commitStr.mid(i, ucWidth);
             const QByteArray oneChar = textAsBytes(oneCharUTF16);
             const int oneCharLen = oneChar.length();
 
-            sci->AddCharUTF(oneChar.data(), oneCharLen);
+            sci->AddCharUTF(oneChar.data(), oneChar.length());
             i += ucWidth;
         }
 
     } else if (!event->preeditString().isEmpty()) {
         const QString preeditStr = event->preeditString();
-        const unsigned int preeditStrLen = preeditStr.length();
-        if ((preeditStrLen == 0) || (preeditStrLen > MAXLENINPUTIME)) {
+        const int preeditStrLen = preeditStr.length();
+        if (preeditStrLen == 0) {
             sci->ShowCaretAtCurrentPosition();
             return;
         }
 
+        if (initialCompose)
+            sci->ClearBeforeTentativeStart();
         sci->pdoc->TentativeStart(); // TentativeActive() from now on.
 
         std::vector<int> imeIndicator = MapImeIndicators(event);
 
-        const bool recording = sci->recordingMacro;
-        sci->recordingMacro = false;
         for (unsigned int i = 0; i < preeditStrLen;) {
             const unsigned int ucWidth = preeditStr.at(i).isHighSurrogate() ? 2 : 1;
             const QString oneCharUTF16 = preeditStr.mid(i, ucWidth);
@@ -186,7 +187,6 @@ void QsciScintillaBase::inputMethodEvent(QInputMethodEvent *event)
             DrawImeIndicator(sci, imeIndicator[i], oneCharLen);
             i += ucWidth;
         }
-        sci->recordingMacro = recording;
 
         // Move IME carets.
         int imeCaretPos = GetImeCaretPos(event);

+ 2 - 2
src/qscint/src/ListBoxQt.cpp

@@ -1,7 +1,7 @@
-// This module implements the specialisation of QListBox that handles the
+// This module implements the specialisation of QListBox that handles the
 // Scintilla double-click callback.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/ListBoxQt.h

@@ -1,7 +1,7 @@
-// This defines the specialisation of QListBox that handles the Scintilla
+// This defines the specialisation of QListBox that handles the Scintilla
 // double-click callback.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/MacPasteboardMime.cpp

@@ -1,8 +1,8 @@
-// This module implements part of the support for rectangular selections on
+// This module implements part of the support for rectangular selections on
 // macOS.  It is a separate file to avoid clashes between macOS and Scintilla
 // data types.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/PlatQt.cpp

@@ -1,6 +1,6 @@
-// This module implements the portability layer for the Qt port of Scintilla.
+// This module implements the portability layer for the Qt port of Scintilla.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qsciabstractapis.h

@@ -1,6 +1,6 @@
-// This module defines interface to the QsciAbstractAPIs class.
+// This module defines interface to the QsciAbstractAPIs class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qsciapis.h

@@ -1,6 +1,6 @@
-// This module defines interface to the QsciAPIs class.
+// This module defines interface to the QsciAPIs class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qscicommand.h

@@ -1,6 +1,6 @@
-// This defines the interface to the QsciCommand class.
+// This defines the interface to the QsciCommand class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qscicommandset.h

@@ -1,6 +1,6 @@
-// This defines the interface to the QsciCommandSet class.
+// This defines the interface to the QsciCommandSet class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qscidocument.h

@@ -1,6 +1,6 @@
-// This defines the interface to the QsciDocument class.
+// This defines the interface to the QsciDocument class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 1
src/qscint/src/Qsci/qsciglobal.h

@@ -1,6 +1,6 @@
 // This module defines various things common to all of the Scintilla Qt port.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 
@@ -40,6 +40,7 @@
 #ifdef QSCINTILLA_DLL
 #undef QSCINTILLA_DLL
 #endif
+
 //#define QSCINTILLA_DLL
 
 #if defined(QSCINTILLA_DLL)

+ 1 - 1
src/qscint/src/Qsci/qscilexer.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexer class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qscilexerasm.h

@@ -1,7 +1,7 @@
-#pragma once
+#pragma once
 // This defines the interface to the QsciLexerAsm class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 //
 // This file is part of QScintilla.
 //

+ 1 - 1
src/qscint/src/Qsci/qscilexeravs.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerAVS class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerbash.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerBash class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerbatch.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerBatch class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexercmake.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerCMake class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexercoffeescript.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerCoffeeScript class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexercpp.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerCPP class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexercsharp.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerCSharp class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexercss.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerCSS class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qscilexercustom.h

@@ -1,6 +1,6 @@
-// This defines the interface to the QsciLexerCustom class.
+// This defines the interface to the QsciLexerCustom class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerd.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerD class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qscilexerdiff.h

@@ -1,6 +1,6 @@
-// This defines the interface to the QsciLexerDiff class.
+// This defines the interface to the QsciLexerDiff class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qscilexeredifact.h

@@ -1,6 +1,6 @@
-// This defines the interface to the QsciLexerEDIFACT class.
+// This defines the interface to the QsciLexerEDIFACT class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerfortran.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerFortran class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerfortran77.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerFortran77 class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexergo.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerGO class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerhtml.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerHTML class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexeridl.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerIDL class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerjava.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerJava class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerjavascript.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerJavaScript class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerjson.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerJSON class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerlua.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerLua class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qscilexermakefile.h

@@ -1,6 +1,6 @@
-// This defines the interface to the QsciLexerMakefile class.
+// This defines the interface to the QsciLexerMakefile class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qscilexermarkdown.h

@@ -1,6 +1,6 @@
-// This defines the interface to the QsciLexerMarkdown class.
+// This defines the interface to the QsciLexerMarkdown class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexermatlab.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerMatlab class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexeroctave.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerOctave class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerpascal.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerPascal class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerperl.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerPerl class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qscilexerpo.h

@@ -1,6 +1,6 @@
-// This defines the interface to the QsciLexerPO class.
+// This defines the interface to the QsciLexerPO class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerpostscript.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerPostScript class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerpov.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerPOV class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qscilexerproperties.h

@@ -1,6 +1,6 @@
-// This defines the interface to the QsciLexerProperties class.
+// This defines the interface to the QsciLexerProperties class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerpython.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerPython class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qscilexerr.h

@@ -1,8 +1,8 @@
-#pragma once
+#pragma once
 #pragma once
 // This defines the interface to the QsciLexerR class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 //
 // This file is part of QScintilla.
 //

+ 1 - 1
src/qscint/src/Qsci/qscilexerruby.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerRuby class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerspice.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerSpice class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexersql.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerSQL class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexertcl.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerTCL class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexertex.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerTeX class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerverilog.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerVerilog class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexervhdl.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerVHDL class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexerxml.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerXML class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qscilexeryaml.h

@@ -1,6 +1,6 @@
 // This defines the interface to the QsciLexerYAML class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qscimacro.h

@@ -1,6 +1,6 @@
-// This defines the interface to the QsciMacro class.
+// This defines the interface to the QsciMacro class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qsciprinter.h

@@ -1,6 +1,6 @@
-// This module defines interface to the QsciPrinter class.
+// This module defines interface to the QsciPrinter class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qsciscintilla.h

@@ -1,7 +1,7 @@
 // This module defines the "official" high-level API of the Qt port of
 // Scintilla.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 1 - 1
src/qscint/src/Qsci/qsciscintillabase.h

@@ -1,6 +1,6 @@
 // This class defines the "official" low-level API.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qscistyle.h

@@ -1,6 +1,6 @@
-// This module defines interface to the QsciStyle class.
+// This module defines interface to the QsciStyle class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

+ 2 - 2
src/qscint/src/Qsci/qscistyledtext.h

@@ -1,6 +1,6 @@
-// This module defines interface to the QsciStyledText class.
+// This module defines interface to the QsciStyledText class.
 //
-// Copyright (c) 2021 Riverbank Computing Limited <[email protected]>
+// Copyright (c) 2023 Riverbank Computing Limited <[email protected]>
 // 
 // This file is part of QScintilla.
 // 

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.