qscidisplaywindow.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. #include "qscidisplaywindow.h"
  2. #include "MediatorDisplay.h"
  3. #include "textfind.h"
  4. #include "common.h"
  5. #include "styleset.h"
  6. #include <QScrollBar>
  7. #include <QFileInfo>
  8. #include <QProcess>
  9. #include <QMessageBox>
  10. #include <stdexcept>
  11. QsciDisplayWindow::QsciDisplayWindow(QWidget *parent):QsciScintilla(parent), m_textFindWin(nullptr), m_preFirstLineNum(0), m_isShowFindItem(true)
  12. {
  13. //20210815 左右行同步还有问题,暂时不屏蔽,不实现
  14. connect(this->verticalScrollBar(), &QScrollBar::valueChanged, this, &QsciDisplayWindow::slot_scrollYValueChange);
  15. connect(this->horizontalScrollBar(), &QScrollBar::valueChanged, this, &QsciDisplayWindow::slot_scrollXValueChange);
  16. setAcceptDrops(false);
  17. m_findStartPos = 0;
  18. m_findEndPos = 0;
  19. m_findCurPos = 0;
  20. m_pScintillaFunc = (SCINTILLA_FUNC)this->SendScintillaPtrResult(SCI_GETDIRECTFUNCTION);
  21. m_pScintillaPtr = (SCINTILLA_PTR)this->SendScintillaPtrResult(SCI_GETDIRECTPOINTER);
  22. if (!m_pScintillaFunc)
  23. {
  24. throw std::runtime_error("ScintillaEditView::init : SCI_GETDIRECTFUNCTION message failed");
  25. }
  26. if (!m_pScintillaPtr)
  27. {
  28. throw std::runtime_error("ScintillaEditView::init : SCI_GETDIRECTPOINTER message failed");
  29. }
  30. //这个无比要设置false,否则双击后高亮单词,拷贝时会拷贝多个选择。
  31. execute(SCI_SETMULTIPLESELECTION, false);
  32. execute(SCI_SETMULTIPASTE, 1);
  33. execute(SCI_SETADDITIONALCARETSVISIBLE, false);
  34. execute(SCI_SETSELFORE, true, 0x0);
  35. execute(SCI_SETSELBACK, true, 0x00ffff);
  36. QColor foldfgColor(StyleSet::foldfgColor);
  37. QColor foldbgColor(StyleSet::foldbgColor);//默认0xff,0xff,0xff
  38. //通过fold发现,尽量使用qscint的功能,因为他做了大量封装和简化
  39. setFolding(BoxedTreeFoldStyle, 2);
  40. setFoldMarginColors(foldfgColor, foldbgColor);
  41. setMarginsBackgroundColor(StyleSet::marginsBackgroundColor); //0xea, 0xf7, 0xff //默认0xf0f0f0
  42. connect(this, &QsciDisplayWindow::delayWork, this, &QsciDisplayWindow::slot_delayWork, Qt::QueuedConnection);
  43. }
  44. QsciDisplayWindow::~QsciDisplayWindow()
  45. {
  46. if (m_textFindWin != nullptr)
  47. {
  48. delete m_textFindWin;
  49. m_textFindWin = nullptr;
  50. }
  51. }
  52. void QsciDisplayWindow::setIsShowFindItem(bool v)
  53. {
  54. m_isShowFindItem = v;
  55. }
  56. sptr_t QsciDisplayWindow::execute(quint32 Msg, uptr_t wParam, sptr_t lParam) const {
  57. try {
  58. return (m_pScintillaFunc) ? m_pScintillaFunc(m_pScintillaPtr, Msg, wParam, lParam) : -1;
  59. }
  60. catch (...)
  61. {
  62. return -1;
  63. }
  64. };
  65. void QsciDisplayWindow::mouseDoubleClickEvent(QMouseEvent * e)
  66. {
  67. QsciScintilla::mouseDoubleClickEvent(e);
  68. if (hasSelectedText())
  69. {
  70. emit delayWork();
  71. }
  72. }
  73. const int MAXLINEHIGHLIGHT = 400;
  74. void QsciDisplayWindow::slot_delayWork()
  75. {
  76. if (!hasSelectedText())
  77. {
  78. return;
  79. }
  80. QString word = selectedText();
  81. if (!word.isEmpty())
  82. {
  83. QVector<int>resultPos;
  84. resultPos.reserve(50);
  85. int firstLine = execute(SCI_GETFIRSTVISIBLELINE);
  86. int nbLineOnScreen = execute(SCI_LINESONSCREEN);
  87. int nbLines = std::min(nbLineOnScreen, MAXLINEHIGHLIGHT) + 1;
  88. int lastLine = firstLine + nbLines;
  89. long startPos = execute(SCI_POSITIONFROMLINE, firstLine);
  90. long endPos = execute(SCI_POSITIONFROMLINE, lastLine);
  91. if (endPos == -1)
  92. {
  93. endPos = execute(SCI_GETLENGTH);
  94. }
  95. int curpos = execute(SCI_GETCURRENTPOS);
  96. int mainSelect = 1;
  97. struct Sci_TextToFind findOptions;
  98. findOptions.chrg.cpMin = startPos;
  99. findOptions.chrg.cpMax = endPos;
  100. std::string wordStr = word.toStdString();
  101. findOptions.lpstrText = wordStr.c_str();
  102. int pos = execute(SCI_FINDTEXT, SCFIND_MATCHCASE | SCFIND_WHOLEWORD, reinterpret_cast<sptr_t>(&findOptions));
  103. while (pos != -1)
  104. {
  105. resultPos.append(pos);
  106. if (pos <= curpos)
  107. {
  108. mainSelect = resultPos.size();
  109. }
  110. findOptions.chrg.cpMin = findOptions.chrgText.cpMax;
  111. pos = execute(SCI_FINDTEXT, SCFIND_MATCHCASE | SCFIND_WHOLEWORD, reinterpret_cast<sptr_t>(&findOptions));
  112. }
  113. for (int i = 0, size = resultPos.size(); i < size; ++i)
  114. {
  115. execute(SCI_ADDSELECTION, resultPos.at(i), resultPos.at(i) + word.size());
  116. }
  117. if (!resultPos.isEmpty())
  118. {
  119. execute(SCI_SETMAINSELECTION, mainSelect - 1);
  120. }
  121. }
  122. }
  123. void QsciDisplayWindow::setMediator(MediatorDisplay* mediator)
  124. {
  125. m_mediator = mediator;
  126. }
  127. //滚动条值变化后的槽函数。一旦滚动则会出发这里,发送消息给中介,让中介去同步另外一方
  128. void QsciDisplayWindow::slot_scrollYValueChange(int value)
  129. {
  130. if (m_direction == RC_LEFT)
  131. {
  132. if (m_mediator->getLeftScrollValue() != value)
  133. {
  134. m_mediator->setLeftScrollValue(value);
  135. }
  136. }
  137. else
  138. {
  139. if (m_mediator->getRightScrollValue() != value)
  140. {
  141. m_mediator->setRightScrollValue(value);
  142. }
  143. }
  144. autoAdjustLineWidth(value);
  145. slot_delayWork();
  146. //qDebug("-- dir s n %d %d", m_direction, contentY());
  147. }
  148. //根据现有滚动条来决定是否更新屏幕线宽长度。每滚动2000个单位必须调整line宽
  149. void QsciDisplayWindow::autoAdjustLineWidth(int xScrollValue)
  150. {
  151. if (std::abs(xScrollValue - m_preFirstLineNum) > 400)
  152. {
  153. m_preFirstLineNum = xScrollValue;
  154. updateLineNumberWidth();
  155. }
  156. }
  157. //
  158. //int nbDigitsFromNbLines(size_t nbLines)
  159. //{
  160. // int nbDigits = 0; // minimum number of digit should be 4
  161. // if (nbLines < 10) nbDigits = 1;
  162. // else if (nbLines < 100) nbDigits = 2;
  163. // else if (nbLines < 1000) nbDigits = 3;
  164. // else if (nbLines < 10000) nbDigits = 4;
  165. // else if (nbLines < 100000) nbDigits = 5;
  166. // else if (nbLines < 1000000) nbDigits = 6;
  167. // else // rare case
  168. // {
  169. // nbDigits = 7;
  170. // nbLines /= 1000000;
  171. //
  172. // while (nbLines)
  173. // {
  174. // nbLines /= 10;
  175. // ++nbDigits;
  176. // }
  177. // }
  178. // return nbDigits;
  179. //}
  180. void QsciDisplayWindow::updateLineNumberWidth()
  181. {
  182. auto linesVisible = execute(SCI_LINESONSCREEN);
  183. if (linesVisible)
  184. {
  185. int nbDigits = 0;
  186. auto firstVisibleLineVis = execute(SCI_GETFIRSTVISIBLELINE);
  187. auto lastVisibleLineVis = linesVisible + firstVisibleLineVis + 1;
  188. auto lastVisibleLineDoc = execute(SCI_DOCLINEFROMVISIBLE, lastVisibleLineVis);
  189. nbDigits = nbDigitsFromNbLines(lastVisibleLineDoc);
  190. nbDigits = nbDigits < 3 ? 3 : nbDigits;
  191. auto pixelWidth = 8 + nbDigits * execute(SCI_TEXTWIDTH, STYLE_LINENUMBER, reinterpret_cast<sptr_t>("8"));
  192. execute(SCI_SETMARGINWIDTHN, 3, pixelWidth);
  193. }
  194. }
  195. //X方向滚动条值变化后的槽函数。一旦滚动则会出发这里,发送消息给中介,让中介去同步另外一方
  196. void QsciDisplayWindow::slot_scrollXValueChange(int value)
  197. {
  198. if (m_direction == RC_LEFT)
  199. {
  200. if (m_mediator->getLeftScrollXValue() != value)
  201. {
  202. m_mediator->setLeftScrollXValue(value);
  203. }
  204. }
  205. else
  206. {
  207. if (m_mediator->getRightScrollXValue() != value)
  208. {
  209. m_mediator->setRightScrollXValue(value);
  210. }
  211. }
  212. //qDebug("-- dir s n %d %d", m_direction, contentY());
  213. }
  214. void QsciDisplayWindow::setDirection(RC_DIRECTION direction)
  215. {
  216. m_direction = direction;
  217. }
  218. void QsciDisplayWindow::travEveryBlockToSave(std::function<void(QString&, int)> savefun, QList<BlockUserData*>* externLineInfo)
  219. {
  220. }
  221. int QsciDisplayWindow::getCurVerticalScrollValue()
  222. {
  223. return this->verticalScrollBar()->value();
  224. }
  225. void QsciDisplayWindow::contextUserDefineMenuEvent(QMenu* menu)
  226. {
  227. //QAction* action;
  228. if (menu != nullptr)
  229. {
  230. menu->addAction(tr("Find Text"), this, SLOT(slot_findText()));
  231. menu->addAction(tr("Show File in Explorer"), this, SLOT(slot_showFileInExplorer()));
  232. }
  233. menu->show();
  234. }
  235. void QsciDisplayWindow::inputMethodEvent(QInputMethodEvent* event)
  236. {
  237. if (!event->preeditString().isEmpty())
  238. {
  239. return;
  240. }
  241. QsciScintilla::inputMethodEvent(event);
  242. }
  243. void QsciDisplayWindow::slot_findText()
  244. {
  245. if (m_isShowFindItem)
  246. {
  247. if (m_textFindWin == nullptr)
  248. {
  249. m_textFindWin = new TextFind(m_direction);
  250. connect(m_textFindWin, &TextFind::signFindFile, this, &QsciDisplayWindow::slot_FindTextWithPara);
  251. m_textFindWin->activateWindow();
  252. m_textFindWin->show();
  253. }
  254. else
  255. {
  256. m_textFindWin->activateWindow();
  257. m_textFindWin->showNormal();
  258. }
  259. m_findCurPos = 0;
  260. }
  261. else
  262. {
  263. //不使用这里的查找,直接发信号到外面
  264. emit sign_find();
  265. }
  266. }
  267. void QsciDisplayWindow::slot_FindTextWithPara(int prevOrNext, QString text)
  268. {
  269. std::string str = text.toStdString();
  270. int length = SendScintilla(SCI_GETLENGTH);
  271. if (length > 0)
  272. {
  273. if (prevOrNext == 1)
  274. {
  275. SendScintilla(SCI_SETTARGETSTART, m_findCurPos);
  276. SendScintilla(SCI_SETTARGETEND, length);
  277. int ret = SendScintilla(SCI_SEARCHINTARGET, str.length(), str.c_str());
  278. if (ret >= 0)
  279. {
  280. m_findCurPos = ret + str.length();
  281. SendScintilla(SCI_GOTOPOS, ret);
  282. SendScintilla(SCI_SETSELECTION, ret, ret + str.length());
  283. }
  284. else
  285. {
  286. QMessageBox::information(this, tr("Not Find"), tr("Not Find Next!"));
  287. m_textFindWin->activateWindow();
  288. }
  289. }
  290. else if (prevOrNext == 0)
  291. {
  292. SendScintilla(SCI_SETTARGETSTART, m_findCurPos);
  293. SendScintilla(SCI_SETTARGETEND, 0);
  294. int ret = SendScintilla(SCI_SEARCHINTARGET, str.length(), str.c_str());
  295. if (ret >= 0)
  296. {
  297. m_findCurPos = ret - 1;
  298. SendScintilla(SCI_GOTOPOS, ret);
  299. SendScintilla(SCI_SETSELECTION, ret, ret + str.length());
  300. }
  301. else
  302. {
  303. QMessageBox::information(this, tr("Not Find"), tr("Not Find Prev!"));
  304. m_textFindWin->activateWindow();
  305. }
  306. }
  307. }
  308. }
  309. //定位到文件夹
  310. void QsciDisplayWindow::slot_showFileInExplorer()
  311. {
  312. QString path, cmd;
  313. #ifdef _WIN32
  314. path = m_filePath.replace("/", "\\");
  315. cmd = QString("explorer.exe /select,%1").arg(path);
  316. #else
  317. path = m_filePath.replace("\\", "/");
  318. cmd = QString("open -R %1").arg(path);
  319. #endif
  320. QProcess process;
  321. process.startDetached(cmd);
  322. }