notepad--/qscidisplaywindow.cpp

394 lines
9.7 KiB
C++
Raw Normal View History

#include "qscidisplaywindow.h"
#include "MediatorDisplay.h"
#include "textfind.h"
#include "common.h"
#include "styleset.h"
#include <QScrollBar>
#include <QFileInfo>
#include <QProcess>
#include <QMessageBox>
#include <stdexcept>
QsciDisplayWindow::QsciDisplayWindow(QWidget *parent):QsciScintilla(parent), m_textFindWin(nullptr), m_preFirstLineNum(0), m_isShowFindItem(true)
{
//20210815 左右行同步还有问题,暂时不屏蔽,不实现
connect(this->verticalScrollBar(), &QScrollBar::valueChanged, this, &QsciDisplayWindow::slot_scrollYValueChange);
connect(this->horizontalScrollBar(), &QScrollBar::valueChanged, this, &QsciDisplayWindow::slot_scrollXValueChange);
setAcceptDrops(false);
m_findStartPos = 0;
m_findEndPos = 0;
m_findCurPos = 0;
m_pScintillaFunc = (SCINTILLA_FUNC)this->SendScintillaPtrResult(SCI_GETDIRECTFUNCTION);
m_pScintillaPtr = (SCINTILLA_PTR)this->SendScintillaPtrResult(SCI_GETDIRECTPOINTER);
if (!m_pScintillaFunc)
{
throw std::runtime_error("ScintillaEditView::init : SCI_GETDIRECTFUNCTION message failed");
}
if (!m_pScintillaPtr)
{
throw std::runtime_error("ScintillaEditView::init : SCI_GETDIRECTPOINTER message failed");
}
//这个无比要设置false否则双击后高亮单词拷贝时会拷贝多个选择。
execute(SCI_SETMULTIPLESELECTION, false);
execute(SCI_SETMULTIPASTE, 1);
execute(SCI_SETADDITIONALCARETSVISIBLE, false);
execute(SCI_SETSELFORE, true, 0x0);
execute(SCI_SETSELBACK, true, 0x00ffff);
QColor foldfgColor(StyleSet::foldfgColor);
QColor foldbgColor(StyleSet::foldbgColor);//默认0xff,0xff,0xff
//通过fold发现尽量使用qscint的功能因为他做了大量封装和简化
setFolding(BoxedTreeFoldStyle, 2);
setFoldMarginColors(foldfgColor, foldbgColor);
setMarginsBackgroundColor(StyleSet::marginsBackgroundColor); //0xea, 0xf7, 0xff //默认0xf0f0f0
connect(this, &QsciDisplayWindow::delayWork, this, &QsciDisplayWindow::slot_delayWork, Qt::QueuedConnection);
}
QsciDisplayWindow::~QsciDisplayWindow()
{
if (m_textFindWin != nullptr)
{
delete m_textFindWin;
m_textFindWin = nullptr;
}
}
void QsciDisplayWindow::setIsShowFindItem(bool v)
{
m_isShowFindItem = v;
}
sptr_t QsciDisplayWindow::execute(quint32 Msg, uptr_t wParam, sptr_t lParam) const {
try {
return (m_pScintillaFunc) ? m_pScintillaFunc(m_pScintillaPtr, Msg, wParam, lParam) : -1;
}
catch (...)
{
return -1;
}
};
void QsciDisplayWindow::mouseDoubleClickEvent(QMouseEvent * e)
{
QsciScintilla::mouseDoubleClickEvent(e);
if (hasSelectedText())
{
emit delayWork();
}
}
const int MAXLINEHIGHLIGHT = 400;
void QsciDisplayWindow::slot_delayWork()
{
if (!hasSelectedText())
{
return;
}
QString word = selectedText();
if (!word.isEmpty())
{
QVector<int>resultPos;
resultPos.reserve(50);
int firstLine = execute(SCI_GETFIRSTVISIBLELINE);
int nbLineOnScreen = execute(SCI_LINESONSCREEN);
int nbLines = std::min(nbLineOnScreen, MAXLINEHIGHLIGHT) + 1;
int lastLine = firstLine + nbLines;
long startPos = execute(SCI_POSITIONFROMLINE, firstLine);
long endPos = execute(SCI_POSITIONFROMLINE, lastLine);
if (endPos == -1)
{
endPos = execute(SCI_GETLENGTH);
}
int curpos = execute(SCI_GETCURRENTPOS);
int mainSelect = 1;
struct Sci_TextToFind findOptions;
findOptions.chrg.cpMin = startPos;
findOptions.chrg.cpMax = endPos;
std::string wordStr = word.toStdString();
findOptions.lpstrText = wordStr.c_str();
int pos = execute(SCI_FINDTEXT, SCFIND_MATCHCASE | SCFIND_WHOLEWORD, reinterpret_cast<sptr_t>(&findOptions));
while (pos != -1)
{
resultPos.append(pos);
if (pos <= curpos)
{
mainSelect = resultPos.size();
}
findOptions.chrg.cpMin = findOptions.chrgText.cpMax;
pos = execute(SCI_FINDTEXT, SCFIND_MATCHCASE | SCFIND_WHOLEWORD, reinterpret_cast<sptr_t>(&findOptions));
}
for (int i = 0, size = resultPos.size(); i < size; ++i)
{
execute(SCI_ADDSELECTION, resultPos.at(i), resultPos.at(i) + word.size());
}
if (!resultPos.isEmpty())
{
execute(SCI_SETMAINSELECTION, mainSelect - 1);
}
}
}
void QsciDisplayWindow::setMediator(MediatorDisplay* mediator)
{
m_mediator = mediator;
}
//滚动条值变化后的槽函数。一旦滚动则会出发这里,发送消息给中介,让中介去同步另外一方
void QsciDisplayWindow::slot_scrollYValueChange(int value)
{
if (m_direction == RC_LEFT)
{
if (m_mediator->getLeftScrollValue() != value)
{
m_mediator->setLeftScrollValue(value);
}
}
else
{
if (m_mediator->getRightScrollValue() != value)
{
m_mediator->setRightScrollValue(value);
}
}
autoAdjustLineWidth(value);
slot_delayWork();
//qDebug("-- dir s n %d %d", m_direction, contentY());
}
//根据现有滚动条来决定是否更新屏幕线宽长度。每滚动2000个单位必须调整line宽
void QsciDisplayWindow::autoAdjustLineWidth(int xScrollValue)
{
if (std::abs(xScrollValue - m_preFirstLineNum) > 400)
{
m_preFirstLineNum = xScrollValue;
updateLineNumberWidth();
}
}
//
//int nbDigitsFromNbLines(size_t nbLines)
//{
// int nbDigits = 0; // minimum number of digit should be 4
// if (nbLines < 10) nbDigits = 1;
// else if (nbLines < 100) nbDigits = 2;
// else if (nbLines < 1000) nbDigits = 3;
// else if (nbLines < 10000) nbDigits = 4;
// else if (nbLines < 100000) nbDigits = 5;
// else if (nbLines < 1000000) nbDigits = 6;
// else // rare case
// {
// nbDigits = 7;
// nbLines /= 1000000;
//
// while (nbLines)
// {
// nbLines /= 10;
// ++nbDigits;
// }
// }
// return nbDigits;
//}
void QsciDisplayWindow::updateLineNumberWidth()
{
auto linesVisible = execute(SCI_LINESONSCREEN);
if (linesVisible)
{
int nbDigits = 0;
auto firstVisibleLineVis = execute(SCI_GETFIRSTVISIBLELINE);
auto lastVisibleLineVis = linesVisible + firstVisibleLineVis + 1;
auto lastVisibleLineDoc = execute(SCI_DOCLINEFROMVISIBLE, lastVisibleLineVis);
nbDigits = nbDigitsFromNbLines(lastVisibleLineDoc);
nbDigits = nbDigits < 3 ? 3 : nbDigits;
auto pixelWidth = 8 + nbDigits * execute(SCI_TEXTWIDTH, STYLE_LINENUMBER, reinterpret_cast<sptr_t>("8"));
execute(SCI_SETMARGINWIDTHN, 3, pixelWidth);
}
}
//X方向滚动条值变化后的槽函数。一旦滚动则会出发这里发送消息给中介让中介去同步另外一方
void QsciDisplayWindow::slot_scrollXValueChange(int value)
{
if (m_direction == RC_LEFT)
{
if (m_mediator->getLeftScrollXValue() != value)
{
m_mediator->setLeftScrollXValue(value);
}
}
else
{
if (m_mediator->getRightScrollXValue() != value)
{
m_mediator->setRightScrollXValue(value);
}
}
//qDebug("-- dir s n %d %d", m_direction, contentY());
}
void QsciDisplayWindow::setDirection(RC_DIRECTION direction)
{
m_direction = direction;
}
void QsciDisplayWindow::travEveryBlockToSave(std::function<void(QString&, int)> savefun, QList<BlockUserData*>* externLineInfo)
{
}
int QsciDisplayWindow::getCurVerticalScrollValue()
{
return this->verticalScrollBar()->value();
}
void QsciDisplayWindow::contextUserDefineMenuEvent(QMenu* menu)
{
//QAction* action;
if (menu != nullptr)
{
menu->addAction(tr("Find Text"), this, SLOT(slot_findText()));
menu->addAction(tr("Show File in Explorer"), this, SLOT(slot_showFileInExplorer()));
}
menu->show();
}
void QsciDisplayWindow::inputMethodEvent(QInputMethodEvent* event)
{
if (!event->preeditString().isEmpty())
{
return;
}
QsciScintilla::inputMethodEvent(event);
}
void QsciDisplayWindow::slot_findText()
{
if (m_isShowFindItem)
{
if (m_textFindWin == nullptr)
{
m_textFindWin = new TextFind(m_direction);
connect(m_textFindWin, &TextFind::signFindFile, this, &QsciDisplayWindow::slot_FindTextWithPara);
m_textFindWin->activateWindow();
m_textFindWin->show();
}
else
{
m_textFindWin->activateWindow();
m_textFindWin->showNormal();
}
m_findCurPos = 0;
}
else
{
//不使用这里的查找,直接发信号到外面
emit sign_find();
}
}
void QsciDisplayWindow::slot_FindTextWithPara(int prevOrNext, QString text)
{
std::string str = text.toStdString();
int length = SendScintilla(SCI_GETLENGTH);
if (length > 0)
{
if (prevOrNext == 1)
{
SendScintilla(SCI_SETTARGETSTART, m_findCurPos);
SendScintilla(SCI_SETTARGETEND, length);
int ret = SendScintilla(SCI_SEARCHINTARGET, str.length(), str.c_str());
if (ret >= 0)
{
m_findCurPos = ret + str.length();
SendScintilla(SCI_GOTOPOS, ret);
SendScintilla(SCI_SETSELECTION, ret, ret + str.length());
}
else
{
QMessageBox::information(this, tr("Not Find"), tr("Not Find Next!"));
m_textFindWin->activateWindow();
}
}
else if (prevOrNext == 0)
{
SendScintilla(SCI_SETTARGETSTART, m_findCurPos);
SendScintilla(SCI_SETTARGETEND, 0);
int ret = SendScintilla(SCI_SEARCHINTARGET, str.length(), str.c_str());
if (ret >= 0)
{
m_findCurPos = ret - 1;
SendScintilla(SCI_GOTOPOS, ret);
SendScintilla(SCI_SETSELECTION, ret, ret + str.length());
}
else
{
QMessageBox::information(this, tr("Not Find"), tr("Not Find Prev!"));
m_textFindWin->activateWindow();
}
}
}
}
//定位到文件夹
void QsciDisplayWindow::slot_showFileInExplorer()
{
QString path, cmd;
#ifdef _WIN32
path = m_filePath.replace("/", "\\");
cmd = QString("explorer.exe /select,%1").arg(path);
#else
path = m_filePath.replace("\\", "/");
cmd = QString("open -R %1").arg(path);
#endif
QProcess process;
process.startDetached(cmd);
}