Merge branch 'master' into cmake-dev

* master:
  更新2.0新插件说明,插件可发送消息给主程序执行功能
  一次性整体提交v2.0的代码;基础版功能全部提交完毕。
  update README.md.
  update README.md.
  update README_EN.md. 把英文版本描述信息的措辞修改了一下。
  update README_EN.md.
  修改到实时最新
  update README.md.
  update README.md.
This commit is contained in:
zinface 2023-05-24 10:09:39 +08:00
commit 7d04a3217a
179 changed files with 9059 additions and 6768 deletions

View File

@ -18,11 +18,9 @@
您可以在这个项目提交bug或反馈问题。
最新版本下载地址https://gitee.com/cxasm/notepad--/releases/tag/v1.22
最新版本下载地址https://gitee.com/cxasm/notepad--/releases/latest
最新内测版本下载地址https://gitee.com/cxasm/notepad--/releases/tag/v1.23
NDD已初步推出插件编写功能希望广大的CPP/QT开发者加入我们插件功能均可以留上您的大名和捐赠渠道希望
NDD 具备插件编写功能希望广大的CPP/QT开发者加入我们插件功能均可以留上您的大名和捐赠渠道希望
开发者参与插件功能开发。
做国人自己的免费编辑器,离不开您的支持,请通过微信捐赠我们。
@ -159,10 +157,18 @@ QQ群 616606091 开发群建议懂CPP/QT、愿意参与NDD项目代码贡献
## 效果预览
![输入图片说明](png/20221107_160824.png)
**windows效果图**
![输入图片说明](png/11.png.png)
![输入图片说明](png/6.png)
**MacOS 效果图:**
![Mac系统运行图](png/%E6%88%AA%E5%B1%8F2023-02-26%2011.41.20.png)
![Mac系统文件对比图](png/%E6%88%AA%E5%B1%8F2023-02-26%2011.45.48.png)
![Mac系统文件对比图](png/%E6%88%AA%E5%B1%8F2023-02-26%2011.45.48.png)
**Redhat7.x 效果图:**
![输入图片说明](png/10.png.png)

View File

@ -4,19 +4,17 @@
## Project Introduction
Introducing Notepad-- a text editor written in C++ that works seamlessly across Windows, Linux, and Mac platforms. Our aim is to eventually surpass Notepad++, with a particular focus on the Chinese UOS operating system. Unlike Notepad++, our advantage lies in our cross-platform compatibility and support for various OSes.
Introducing Notepad-- a text editor written in C++ that works seamlessly across Windows, Linux, and Mac platforms. Our goal is to eventually surpass Notepad++, with a special focus on the Chinese UOS operating system. Unlike Notepad++, our advantage lies in our cross-platform compatibility and support for different operating system.
**The purpose of Notepad-- is to counteract some of the misguided remarks made by the author of Notepad++ and to promote a more humble and grounded perspective.**
**The purpose of Notepad-- is to counteract some of the misleading statements made by the author of Notepad++ and to promote a more humble and grounded perspective.**
If you come across any bugs or have any feedback, feel free to share it with us.
If you come across any bugs or have any feedback, feel free to let us know.
You can download the latest version at https://gitee.com/cxasm/notepad--/releases/tag/v1.21.
You can download the latest version from https://gitee.com/cxasm/notepad--/releases/tag/v2.0.
The latest development version can be found at https://gitee.com/cxasm/notepad--/releases/tag/v1.22.
We have recently added the ability to write plugins to Notepad-- and we hope that many CPP/QT developers will join us in this endeavour. If you develop a plugin, you can include your name and a donation channel.
We have recently added the plugin writing feature to Notepad-- and we hope that many CPP/QT developers will join us in this endeavor. If you develop a plugin, you can include your name and a donation channel.
Creating a free text editor requires support from users like you. If you'd like to contribute, please consider donating through WeChat.
Creating a free text editor requires support from users like you. If you'd like to contribute, please consider donating via WeChat.
![Input description picture](6688.png)

BIN
png/10.png.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

BIN
png/11.png.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

BIN
png/9.png.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

View File

@ -992,7 +992,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);
@ -1060,8 +1062,10 @@ CODE_ID CmpareMode::scanFileRealCode(QString filePath)
++lineNums;
//最多扫描200行加块速度。速度与精确性的权衡
if (lineNums >= 200)
//默认最多扫描200行加块速度。速度与精确性的权衡
//对于打开文件默认扫描前面的200行加快速度。
//对于编码转换,为了精确,默认全部都要处理
if ((scanLineNum != -1) && (lineNums >= scanLineNum))
{
break;
}
@ -1103,3 +1107,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;
}

View File

@ -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);

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 652 B

After

Width:  |  Height:  |  Size: 848 B

View File

@ -194,7 +194,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);
@ -454,6 +454,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; //显示空白
@ -1505,14 +1507,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);
@ -1785,8 +1780,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
{
@ -1809,8 +1806,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
{
@ -2158,7 +2156,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;
}
@ -3380,6 +3378,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;
@ -3542,7 +3548,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();
@ -3557,16 +3564,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)
{
@ -3579,17 +3605,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())
{
@ -3601,8 +3654,6 @@ bool CCNotePad::checkRoladFile(ScintillaEditView* pEdit)
m_isInReloadFile = true;
QString filePath = pEdit->property(Edit_View_FilePath).toString();
int tailStatus = getFileTailProperty(pEdit);
if (tailStatus != 1)
@ -3610,25 +3661,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)
{
@ -3638,8 +3702,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);
}
@ -3702,7 +3768,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);
}
//编辑框文本变化后,设置对应的变化状态
@ -3909,10 +3976,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);
@ -3922,7 +4001,7 @@ void CCNotePad::tabClose(int index, bool isInQuit)
return;
}
}
else if (ret == 2)
else if (ret == QMessageBox::Cancel)
{
m_isQuitCancel = true;
return;
@ -4012,7 +4091,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));
}
@ -4165,9 +4249,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)
{
@ -4531,11 +4615,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)
{
//可能存在乱码,给出警告。还是以编辑模式打开
@ -5158,7 +5242,7 @@ bool CCNotePad::tryRestoreFile(QString filePath)
bool CCNotePad::openFile(QString filePath, int lineNum)
{
s_padTimes++;
//如果是相对路径
getRegularFilePath(filePath);
QFileInfo fi(filePath);
@ -5231,6 +5315,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);
@ -5248,6 +5337,7 @@ void CCNotePad::slot_actionOpenFile_toggle(bool /*checked*/)
}
}
#if 0
#ifdef _WIN32
void hide_file(const QString& szFile)
{
@ -5259,12 +5349,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);
@ -5398,7 +5489,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);
@ -5410,10 +5501,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;
@ -6117,6 +6216,8 @@ void CCNotePad::closeFileStatic(int index, QSettings& qs)
removeWatchFilePath(filePath);
pw->deleteLater();
}
void CCNotePad::closeAllFileStatic()
{
QString tempFileList = QString("notepad/temp/list");
@ -6279,8 +6380,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);
@ -6652,7 +6757,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的否则多线程获取不到该变化
//使用了原子变量,效果是一样的,多个线程均可见
@ -6811,15 +6920,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);
@ -6923,6 +7038,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();
}
@ -7014,8 +7136,8 @@ void CCNotePad::clearHighlightWord(QString signWord, ScintillaEditView* pEdit)
delete r;
curMarkRecord.removeAt(i);
}
}
void CCNotePad::slot_clearWordHighlight()
{
QWidget* pw = ui.editTabWidget->currentWidget();
@ -7155,7 +7277,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);
});
@ -7269,16 +7393,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)
{
@ -7546,11 +7716,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);
@ -7945,15 +8115,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
@ -8024,6 +8194,11 @@ void CCNotePad::dropEvent(QDropEvent* e)
e->accept();
}
void CCNotePad::dragLeaveEvent(QDragLeaveEvent* event)
{
qDebug() << "drag level";
}
//目前只有一个Tabwidget的双击事件。
bool CCNotePad::eventFilter(QObject * watched, QEvent * event)
{
@ -8519,7 +8694,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);
@ -8549,10 +8724,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)
{
@ -9646,6 +9825,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);
@ -9653,3 +9872,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

View File

@ -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
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
@ -239,7 +241,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);
@ -351,6 +355,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();
@ -358,7 +364,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();
@ -400,11 +406,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);
@ -475,6 +485,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;
@ -525,6 +536,10 @@ private:
QSharedMemory* m_shareMem;
QList<CompareDirs*> m_cmpDirMgr;
QList<CompareWin*> m_cmpFileMgr;
//最近打开的对比文件和目录列表。做一个环形区
//保存在数据库中
@ -555,6 +570,7 @@ private:
QPointer<QWidget> m_pHexGotoWin;
static QStringList s_findHistroy;
static QStringList s_replaceHistroy;
static int s_padTimes;
int m_curSoftLangs; //当前语言0:自动 1 中文 2 英语
@ -619,6 +635,7 @@ private:
QList<NDD_PROC_DATA> m_pluginList;
public:
static QString s_lastOpenDirPath;
static int s_restoreLastFile; //自动恢复上次打开的文件
static int s_curStyleId;

View File

@ -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">

View File

@ -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,6 +470,172 @@ int FileManager::loadFileDataInText(ScintillaEditView* editView, QString filePat
return 0;
}
#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);
//直接以只读的方式打开,至于能不能保存,是保存时需要考虑的问题。
//只需要在保存的时候获取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)
{
@ -413,15 +643,9 @@ int FileManager::loadFileForSearch(ScintillaEditView* editView, QString filePath
QFlags<QFileDevice::Permission> power = QFile::permissions(filePath);
if (!power.testFlag(QFile::ReadOwner))
{
//文件不能读
return 1;
}
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;
}

View File

@ -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;

View File

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

View File

@ -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());
}
}
}

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -290,7 +290,7 @@ QFuture<EncodeThreadParameter*> EncodeConvert::commitTask(std::function<EncodeTh
}
//对比左右文件的大小sha1值来判断文件是否相等
//识别文件编码
QFuture<EncodeThreadParameter_*> EncodeConvert::checkFileCode(QString filePath, QTreeWidgetItem* item)
{
EncodeThreadParameter_* p = new EncodeThreadParameter_(filePath);
@ -299,7 +299,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);
@ -474,6 +475,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
src/findresultview.cpp Executable file
View File

@ -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
src/findresultview.h Executable file
View File

@ -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;
};

View File

@ -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);
}
}
clear();
}
void FindResultWin::slot_treeView_pressed(QModelIndex modeIndex)
void FindResultWin::clear()
{
ui.resultTreeView->resizeColumnToContents(modeIndex.column());
}
void FindResultWin::contextMenuEvent(QContextMenuEvent *)
{
if (m_menu == nullptr)
for (int i = 0; i < m_resultLineFilePath.size(); ++i)
{
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);
delete m_resultLineFilePath.at(i);
}
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());
}
}
}
}
}
//全选
void FindResultWin::slot_selectAll()
{
QModelIndex root = ui.resultTreeView->rootIndex();
QModelIndex curSelItem = ui.resultTreeView->currentIndex();
QModelIndex firstRootItem;
//先找到根节点
while (curSelItem.isValid())
{
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");
}
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)
{
@ -475,7 +158,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));
@ -509,36 +192,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 = 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)
{
FindRecord v = record->records.at(i);
const QString & richText = v.lineContents;
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;
//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
{
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());
}*/
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());
QStandardItem* titleItem = new QStandardItem(findTitle);
//if (!StyleSet::isCurrentDeepStyle())
//{
setItemBackground(titleItem, QColor(0xbbbbff));
//}
//else
//{
// setItemBackground(titleItem, QColor(0x423328));//0xd5ffd5
//}
setItemBackground(titleItem, QColor(0xbbbbff));
m_model->insertRow(0, titleItem);
titleItem->setData(QVariant(true), ResultItemRoot);
@ -587,8 +302,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)
{
@ -617,8 +330,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)
{
@ -627,149 +341,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);
//总是把结果插在最上面一行
m_model->insertRow(0, titleItem);
int rowNum = m_model->rowCount();
//把其余的行收起来
for (int i = 1; i < rowNum; ++i)
if (this->isHidden())
{
ui.resultTreeView->collapse(m_model->index(i, 0));
this->setVisible(true);
}
ui.resultTreeView->expand(m_model->index(0, 0));
ResultLineInfo lineInfo;
QString findTitle = tr("Search \"%1\" (%2 hits in %3 files)\n").arg(whatFind).arg(hits).arg(record->size());
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());
desc = tr(" %1 (%2 hits)\n").arg(pr->findFilePath).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());
desc = tr(" %1 (%2 hits)\n").arg(pr->findFilePath).arg(pr->records.size());
}
contents.append(desc);
m_resultLineFilePath.append(pFilePath);
QStandardItem* descItem = new QStandardItem(desc);
lineInfo.level = 1;
m_resultLineInfo.insert(insertIndex, lineInfo);
++insertIndex;
if (!StyleSet::isCurrentDeepStyle())
for (int j = 0; j < pr->records.size(); ++j)
{
setItemBackground(descItem, QColor(0xd5ffd5));
}
else
{
setItemBackground(descItem, QColor(0x484848));
}
FindRecord v = pr->records.at(j);
QString richText = v.lineContents;
titleItem->insertRow(0,descItem);
linePrefix = tr(" Line %1: ").arg(v.lineNum + 1);
//默认全部收起来
if (count > 10)
{
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);
//描述行双击不响应
descItem->setData(QVariant(true), ResultItemDesc);
for (int i = 0; i < pr->records.size(); ++i)
{
FindRecord v = pr->records.at(i);
QString richText = highlightFindText(v);
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())
}
pDisplay->insertAt(contents.join(""), 1, 0);
int lineNum = 1;
QList<int> destFileLineNum;
for (int i = 0, count = record->size(); i < count; ++i)
{
FindRecords* pr = record->at(i);
pDisplay->SendScintilla(SCI_SETFOLDLEVEL, lineNum, (long)(1 | SC_FOLDLEVELHEADERFLAG));
destFileLineNum.append(lineNum);
++lineNum;
for (int j = 0; j < pr->records.size(); ++j)
{
ui.resultTreeView->expand(m_model->index(0, 0, m_model->index(0, 0)));
pDisplay->SendScintilla(SCI_SETFOLDLEVEL, lineNum, (long)2| SC_FOLDLEVELBASE);
++lineNum;
}
}
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->setLineBackColorStyle(0, STYLE_COLOUR_TITLE);
void FindResultWin::setItemForeground(QStandardItem* item, const QColor& color)
{
QBrush b(color);
item->setForeground(b);
}
//查找结果框的字体变大
void FindResultWin::slot_fontZoomIn()
{
QFont curFt = ui.resultTreeView->font();
int s = curFt.pointSize();
s += 2;
curFt.setPointSize(s);
m_defaultFontSize += 2;
ui.resultTreeView->setFont(curFt);
m_delegate->setFontSize(m_defaultFontSize);
m_defFontSizeChange = true;
}
void FindResultWin::slot_fontZoomOut()
{
QFont curFt = ui.resultTreeView->font();
int s = curFt.pointSize();
s -= 2;
if (s >= 8)
for (int i = 0, count = destFileLineNum.size(); i < count; ++i)
{
m_defFontSizeChange = true;
m_defaultFontSize -= 2;
curFt.setPointSize(s);
ui.resultTreeView->setFont(curFt);
m_delegate->setFontSize(m_defaultFontSize);
pDisplay->setLineBackColorStyle(destFileLineNum.at(i), (StyleSet::isCurrentDeepStyle()? STYLE_DEEP_COLOUR_DEST_FILE:STYLE_COLOUR_DEST_FILE));
}
//关键字高亮
//高亮的开始、结束位置
int targetStart = 0;
int targetLens = 0;
lineNum = 1;
int lineOffsetPosIndex = 0;
int lineOffsetPos = 0;
QString lineNumStr = tr(" Line ");
int skipLineNumOffset = lineNumStr.toUtf8().size();
for (int i = 0, count = record->size(); i < count; ++i)
{
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;
@ -779,3 +493,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);
}
}
}

View File

@ -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;
QStandardItemModel* m_model;
NdStyledItemDelegate* m_delegate;
QWidget* m_parent;
QList<ResultLineInfo> m_resultLineInfo;
QList<QString*> m_resultLineFilePath;
int m_defaultFontSize;
bool m_defFontSizeChange;
};

View File

@ -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>
<enum>QFrame::StyledPanel</enum>
</property>
<property name="lineWidth">
<number>1</number>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::DoubleClicked</set>
</property>
<property name="animated">
<bool>true</bool>
</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/>

View File

@ -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()
@ -881,7 +945,7 @@ void FindWin::removeEmptyLine(bool isBlankContained)
{
ui.replaceTextBox->setCurrentText("^$(\\r\\n|\\r|\\n)");
}
ui.replaceWithBox->setText("");
ui.replaceWithBox->setEditText("");
ui.replaceModeRegularBt->setChecked(true);
@ -974,8 +1038,6 @@ void FindWin::dofindNext()
updateParameterFromUI();
QWidget* pw = autoAdjustCurrentEditWin();
QsciScintilla* pEdit = dynamic_cast<QsciScintilla*>(pw);
//第一次查找
@ -1100,7 +1162,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;
@ -1124,11 +1186,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
{
@ -1170,11 +1232,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);
@ -1558,8 +1625,8 @@ int FindWin::findAllInCurDoc(QStringList* reResult)
if (!m_isStatic)
{
QApplication::beep();
emit sign_findAllInCurDoc(&results);
QApplication::beep();
emit sign_findAllInCurDoc(&results);
}
m_isFindFirst = true;
@ -1609,7 +1676,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;
@ -1642,11 +1709,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);
@ -1726,7 +1892,7 @@ void FindWin::slot_findAllInOpenDoc()
}
delete allOpenFileRecord;
#endif
}
//返回是否查找得到内容
@ -1744,6 +1910,9 @@ bool FindWin::replaceFindNext(QsciScintilla* pEdit, bool showZeroFindTip)
addFindHistory(whatFind);
QString replaceWith = ui.replaceWithBox->currentText();
addReplaceHistory(replaceWith);
if (m_extend)
{
QString extendFind;
@ -1820,7 +1989,7 @@ bool FindWin::replace(ScintillaEditView* pEdit)
}
QString findText = ui.replaceTextBox->currentText();
QString replaceText = ui.replaceWithBox->text();
QString replaceText = ui.replaceWithBox->currentText();
if (m_extend)
{
@ -2083,7 +2252,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);
@ -2147,14 +2316,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;
}
@ -2186,7 +2353,7 @@ int FindWin::replaceAll()
updateParameterFromUI();
QString whatFind = ui.replaceTextBox->currentText();
QString replaceText = ui.replaceWithBox->text();
QString replaceText = ui.replaceWithBox->currentText();
if (m_extend)
{
@ -2290,7 +2457,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())
{
@ -2367,6 +2534,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())
@ -2374,15 +2546,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
@ -2431,6 +2603,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;
}
@ -2517,31 +2693,15 @@ bool FindWin::replaceTextInFile(QString &filePath, int &replaceNums, QVector<Fin
replace = extendReplace;
}
replaceNums += doReplaceAll(pEditTemp, find, replace);
int modifyTimes = doReplaceAll(pEditTemp, find, replace);
#if 0
if (!pEditTemp->findFirst(find, m_re, m_cs, m_wo, false, m_forward, FINDNEXTTYPE_REPLACENEXT,0, 0,false))
if (modifyTimes > 0)
{
return false;
replaceNums += modifyTimes;
//如果进行过替换,则必须要保存一下;否则不能保存,不然文件被修改。
emit sign_replaceSaveFile(filePath, pEditTemp);
}
pEditTemp->replace(replace);
dealWithZeroFound(pEditTemp);
++replaceNums;
//找到了,则自动进行全部替换
while (pEditTemp->findNext())
{
pEditTemp->replace(replace);
++replaceNums;
dealWithZeroFound(pEditTemp);
}
#endif
//必须要保存一下
emit sign_replaceSaveFile(filePath, pEditTemp);
return true;
}
@ -2853,7 +3013,7 @@ void FindWin::slot_dirFindAll()
if (pEditTemp == nullptr)
{
pEditTemp = new ScintillaEditView(nullptr);
pEditTemp = ScintillaEditView::createEditForSearch();
}
int foundNums = 0;
@ -2865,7 +3025,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);
@ -2887,7 +3047,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())
{
@ -2969,12 +3129,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);
@ -2983,7 +3146,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));
}
@ -3004,4 +3167,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);
}
}

View File

@ -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;

View File

@ -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,48 +759,7 @@
</item>
<item>
<layout class="QGridLayout" name="gridLayout_5">
<item row="1" column="1">
<widget class="QLineEdit" name="fileType">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>350</width>
<height>16777215</height>
</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">
@ -813,20 +772,7 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="skipDir">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Skip Dir Name :</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<widget class="QLineEdit" name="skipDirNames">
<property name="enabled">
<bool>false</bool>
@ -854,8 +800,24 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="dirReplaceWhat">
<item row="3" column="0">
<widget class="QCheckBox" name="skipDir">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Skip Dir Name :</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="fileType">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -874,6 +836,35 @@
<height>16777215</height>
</size>
</property>
<property name="placeholderText">
<string>*.c:*.cpp:*.h</string>
</property>
</widget>
</item>
<item row="2" 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="1" column="1">
<widget class="QComboBox" name="dirReplaceWhat">
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
@ -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>

View File

@ -121,8 +121,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
src/markdownview.cpp Executable file
View File

@ -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
src/markdownview.h Executable file
View File

@ -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
src/markdownview.ui Executable file
View File

@ -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
src/nddpluginapi.cpp Executable file
View File

@ -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
src/nddpluginapi.h Executable file
View File

@ -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;
};

View File

@ -90,10 +90,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");
@ -368,3 +368,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;
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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);

View File

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

View File

@ -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

View File

@ -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在外面会释放。

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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 <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

View File

@ -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 <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

View File

@ -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 <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

View File

@ -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 <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

View File

@ -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 <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

View File

@ -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 <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

View File

@ -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 <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

View File

@ -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 <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

View File

@ -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 <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

View File

@ -1,6 +1,6 @@
// This module defines various things common to all of the Scintilla Qt port.
//
// Copyright (c) 2021 Riverbank Computing Limited <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

View File

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

View File

@ -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 <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

View File

@ -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 <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

View File

@ -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 <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

View File

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

View File

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

View File

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

View File

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

View File

@ -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 <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

View File

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

View File

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

View File

@ -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 <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 <info@riverbankcomputing.com>
// Copyright (c) 2023 Riverbank Computing Limited <info@riverbankcomputing.com>
//
// This file is part of QScintilla.
//

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