feat: 回归代码搜索替换和转到行功能;完成回归文本预览;
This commit is contained in:
parent
b4a03ae827
commit
77bec99ac5
|
@ -177,9 +177,7 @@ set(DIALOG_SRC
|
|||
src/dialog/showtextdialog.cpp
|
||||
src/dialog/showtextdialog.h
|
||||
src/dialog/definitiondownload.cpp
|
||||
src/dialog/definitiondownload.h
|
||||
src/dialog/searchdialog.cpp
|
||||
src/dialog/searchdialog.h)
|
||||
src/dialog/definitiondownload.h)
|
||||
|
||||
set(CONTROL_SRC
|
||||
src/control/codeedit.h
|
||||
|
@ -216,7 +214,13 @@ set(CONTROL_SRC
|
|||
src/control/popupactionwidget.h
|
||||
src/control/popupactionwidget.cpp
|
||||
src/control/settingspopup.cpp
|
||||
src/control/settingspopup.h)
|
||||
src/control/settingspopup.h
|
||||
src/control/searchreplacewidget.cpp
|
||||
src/control/searchreplacewidget.h
|
||||
src/control/gotolinewidget.h
|
||||
src/control/gotolinewidget.cpp
|
||||
src/control/codeeditcontrolwidget.h
|
||||
src/control/codeeditcontrolwidget.cpp)
|
||||
|
||||
set(CLASS_SRC
|
||||
src/class/logger.cpp
|
||||
|
|
|
@ -273,37 +273,37 @@
|
|||
<message>
|
||||
<location filename="../../src/dialog/definitiondownload.cpp" line="43"/>
|
||||
<source>Update Syntax Definitions</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>更新高亮定义</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/definitiondownload.cpp" line="72"/>
|
||||
<source>Updating syntax definitions from online repository...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>从在线存储库更新语法高亮定义...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/definitiondownload.cpp" line="85"/>
|
||||
<source>%1:%2 hours</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1:%2 小时</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/definitiondownload.cpp" line="90"/>
|
||||
<source>%1:%2 minutes</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1:%2 分钟</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/definitiondownload.cpp" line="97"/>
|
||||
<source>%1.%2 seconds</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1:%2 秒</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/definitiondownload.cpp" line="99"/>
|
||||
<source>%1 ms</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1 毫秒</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/definitiondownload.cpp" line="102"/>
|
||||
<source>Update operation completed (%1)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>更新操作已完成(%1)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -681,6 +681,14 @@
|
|||
<translation>全屏</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>GotoLineWidget</name>
|
||||
<message>
|
||||
<location filename="../../src/control/gotolinewidget.cpp" line="32"/>
|
||||
<source>Close</source>
|
||||
<translation>关闭</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>GotoWidget</name>
|
||||
<message>
|
||||
|
@ -4874,140 +4882,87 @@
|
|||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SearchDialog</name>
|
||||
<name>SearchReplaceWidget</name>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="207"/>
|
||||
<source>Find and Replace...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="172"/>
|
||||
<source>Close</source>
|
||||
<translation>关闭</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="213"/>
|
||||
<source>Match ca&se</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="215"/>
|
||||
<source>Match &whole words</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="217"/>
|
||||
<source>Regular e&xpressions</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="219"/>
|
||||
<source>&Escape sequences</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="221"/>
|
||||
<source>Wrap Aro&und</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="232"/>
|
||||
<source>Find &Next</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="234"/>
|
||||
<source>Find &Previous</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="236"/>
|
||||
<source>&Replace</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="238"/>
|
||||
<source>Replace &All</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="240"/>
|
||||
<source>&In Selection</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="244"/>
|
||||
<source>&Close</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="264"/>
|
||||
<source>&Find:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="269"/>
|
||||
<source>Replace wit&h:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="520"/>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="581"/>
|
||||
<source>The specified text was not found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="588"/>
|
||||
<source>The specified text was not found in the selection</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="617"/>
|
||||
<source>Successfully replaced %1 matches</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SearchWidget</name>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="51"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="181"/>
|
||||
<source>Search Settings</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>搜索设置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="56"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="186"/>
|
||||
<source>Match ca&se</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>区分大小写(&S)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="58"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="188"/>
|
||||
<source>Match &whole words</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>全词匹配(&W)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="60"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="190"/>
|
||||
<source>Regular e&xpressions</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>正则表达式(&X)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="62"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="192"/>
|
||||
<source>&Escape sequences</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>转义序列(&E)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="64"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="194"/>
|
||||
<source>Wrap Aro&und</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>环绕(&U)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="86"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="197"/>
|
||||
<source>Replace in selection</source>
|
||||
<translation>选区替换</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="220"/>
|
||||
<source>Find Next</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>查找下一个</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="91"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="225"/>
|
||||
<source>Find Previous</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>查找上一个</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="151"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="237"/>
|
||||
<source>Replace Current</source>
|
||||
<translation>替换当前</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="242"/>
|
||||
<source>Replace All</source>
|
||||
<translation>替换所有</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="258"/>
|
||||
<source>Replace:</source>
|
||||
<translation>替换:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="368"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="430"/>
|
||||
<source>The specified text was not found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>未找到指定文本</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="375"/>
|
||||
<source>The specified text was not found in the selection</source>
|
||||
<translation>在选定内容中未找到指定的文本</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="404"/>
|
||||
<source>Successfully replaced %1 matches</source>
|
||||
<translation>已成功替换 %1 个匹配项</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -5069,7 +5024,7 @@
|
|||
<message>
|
||||
<location filename="../../src/dialog/showtextdialog.cpp" line="107"/>
|
||||
<source>Plain Text</source>
|
||||
<translation type="unfinished">纯文本</translation>
|
||||
<translation>纯文本</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/showtextdialog.cpp" line="116"/>
|
||||
|
@ -5080,7 +5035,7 @@
|
|||
<location filename="../../src/dialog/showtextdialog.cpp" line="121"/>
|
||||
<location filename="../../src/dialog/showtextdialog.cpp" line="188"/>
|
||||
<source>Loading...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>加载中...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/showtextdialog.cpp" line="141"/>
|
||||
|
@ -5105,7 +5060,7 @@
|
|||
<message>
|
||||
<location filename="../../src/dialog/showtextdialog.cpp" line="165"/>
|
||||
<source>UpdateDefs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>更新高亮定义</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/showtextdialog.cpp" line="175"/>
|
||||
|
@ -5116,12 +5071,12 @@
|
|||
<context>
|
||||
<name>SkinManager</name>
|
||||
<message>
|
||||
<location filename="../../src/class/skinmanager.cpp" line="67"/>
|
||||
<location filename="../../src/class/skinmanager.cpp" line="78"/>
|
||||
<source>Dark</source>
|
||||
<translation>暗黑</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/class/skinmanager.cpp" line="68"/>
|
||||
<location filename="../../src/class/skinmanager.cpp" line="79"/>
|
||||
<source>Light</source>
|
||||
<translation>浅色</translation>
|
||||
</message>
|
||||
|
|
|
@ -273,37 +273,37 @@
|
|||
<message>
|
||||
<location filename="../../src/dialog/definitiondownload.cpp" line="43"/>
|
||||
<source>Update Syntax Definitions</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>更新高亮定義</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/definitiondownload.cpp" line="72"/>
|
||||
<source>Updating syntax definitions from online repository...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>從線上存儲庫更新語法高亮定義...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/definitiondownload.cpp" line="85"/>
|
||||
<source>%1:%2 hours</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1:%2 小時</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/definitiondownload.cpp" line="90"/>
|
||||
<source>%1:%2 minutes</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1:%2 分鐘</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/definitiondownload.cpp" line="97"/>
|
||||
<source>%1.%2 seconds</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1:%2 秒</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/definitiondownload.cpp" line="99"/>
|
||||
<source>%1 ms</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1 毫秒</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/definitiondownload.cpp" line="102"/>
|
||||
<source>Update operation completed (%1)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>更新操作已完成(%1)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -681,6 +681,14 @@
|
|||
<translation>全屏</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>GotoLineWidget</name>
|
||||
<message>
|
||||
<location filename="../../src/control/gotolinewidget.cpp" line="32"/>
|
||||
<source>Close</source>
|
||||
<translation>關閉</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>GotoWidget</name>
|
||||
<message>
|
||||
|
@ -4874,140 +4882,87 @@
|
|||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SearchDialog</name>
|
||||
<name>SearchReplaceWidget</name>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="207"/>
|
||||
<source>Find and Replace...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="172"/>
|
||||
<source>Close</source>
|
||||
<translation>關閉</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="213"/>
|
||||
<source>Match ca&se</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="215"/>
|
||||
<source>Match &whole words</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="217"/>
|
||||
<source>Regular e&xpressions</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="219"/>
|
||||
<source>&Escape sequences</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="221"/>
|
||||
<source>Wrap Aro&und</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="232"/>
|
||||
<source>Find &Next</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="234"/>
|
||||
<source>Find &Previous</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="236"/>
|
||||
<source>&Replace</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="238"/>
|
||||
<source>Replace &All</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="240"/>
|
||||
<source>&In Selection</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="244"/>
|
||||
<source>&Close</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="264"/>
|
||||
<source>&Find:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="269"/>
|
||||
<source>Replace wit&h:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="520"/>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="581"/>
|
||||
<source>The specified text was not found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="588"/>
|
||||
<source>The specified text was not found in the selection</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="617"/>
|
||||
<source>Successfully replaced %1 matches</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SearchWidget</name>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="51"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="181"/>
|
||||
<source>Search Settings</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>搜索設置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="56"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="186"/>
|
||||
<source>Match ca&se</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>區分大小寫(&S)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="58"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="188"/>
|
||||
<source>Match &whole words</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>全詞匹配(&W)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="60"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="190"/>
|
||||
<source>Regular e&xpressions</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>正則運算式(&X)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="62"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="192"/>
|
||||
<source>&Escape sequences</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>轉義序列(&E)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="64"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="194"/>
|
||||
<source>Wrap Aro&und</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>環繞(&U)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="86"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="197"/>
|
||||
<source>Replace in selection</source>
|
||||
<translation>選區替換</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="220"/>
|
||||
<source>Find Next</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>查找下一個</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="91"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="225"/>
|
||||
<source>Find Previous</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>查找上一個</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/searchdialog.cpp" line="151"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="237"/>
|
||||
<source>Replace Current</source>
|
||||
<translation>替換當前</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="242"/>
|
||||
<source>Replace All</source>
|
||||
<translation>替換所有</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="258"/>
|
||||
<source>Replace:</source>
|
||||
<translation>替換:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="368"/>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="430"/>
|
||||
<source>The specified text was not found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>未找到指定文本</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="375"/>
|
||||
<source>The specified text was not found in the selection</source>
|
||||
<translation>在選定內容中未找到指定的文本</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/control/searchreplacewidget.cpp" line="404"/>
|
||||
<source>Successfully replaced %1 matches</source>
|
||||
<translation>已成功替換 %1 個匹配項</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -5069,7 +5024,7 @@
|
|||
<message>
|
||||
<location filename="../../src/dialog/showtextdialog.cpp" line="107"/>
|
||||
<source>Plain Text</source>
|
||||
<translation type="unfinished">純文字</translation>
|
||||
<translation>純文字</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/showtextdialog.cpp" line="116"/>
|
||||
|
@ -5080,7 +5035,7 @@
|
|||
<location filename="../../src/dialog/showtextdialog.cpp" line="121"/>
|
||||
<location filename="../../src/dialog/showtextdialog.cpp" line="188"/>
|
||||
<source>Loading...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>加載中...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/showtextdialog.cpp" line="141"/>
|
||||
|
@ -5105,7 +5060,7 @@
|
|||
<message>
|
||||
<location filename="../../src/dialog/showtextdialog.cpp" line="165"/>
|
||||
<source>UpdateDefs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>更新高亮定義</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/dialog/showtextdialog.cpp" line="175"/>
|
||||
|
@ -5116,12 +5071,12 @@
|
|||
<context>
|
||||
<name>SkinManager</name>
|
||||
<message>
|
||||
<location filename="../../src/class/skinmanager.cpp" line="67"/>
|
||||
<location filename="../../src/class/skinmanager.cpp" line="78"/>
|
||||
<source>Dark</source>
|
||||
<translation>暗黑</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../src/class/skinmanager.cpp" line="68"/>
|
||||
<location filename="../../src/class/skinmanager.cpp" line="79"/>
|
||||
<source>Light</source>
|
||||
<translation>淺色</translation>
|
||||
</message>
|
||||
|
|
|
@ -61,6 +61,17 @@ SkinManager &SkinManager::instance() {
|
|||
|
||||
void SkinManager::setTheme(SkinManager::Theme theme) { m_theme = theme; }
|
||||
|
||||
QIcon SkinManager::themeIcon(const QString &name) {
|
||||
switch (m_theme) {
|
||||
case Theme::Dark:
|
||||
return QIcon(QStringLiteral("://dark/") + name +
|
||||
QStringLiteral(".svg"));
|
||||
case Theme::Light:
|
||||
return QIcon(QStringLiteral("://light/") + name +
|
||||
QStringLiteral(".svg"));
|
||||
}
|
||||
}
|
||||
|
||||
SkinManager::Theme SkinManager::currentTheme() const { return m_theme; }
|
||||
|
||||
void SkinManager::translate() {
|
||||
|
|
|
@ -37,6 +37,8 @@ public:
|
|||
void setTheme(Theme theme);
|
||||
Theme currentTheme() const;
|
||||
|
||||
QIcon themeIcon(const QString &name);
|
||||
|
||||
private:
|
||||
Q_DECL_UNUSED void translate();
|
||||
|
||||
|
|
|
@ -16,12 +16,15 @@
|
|||
*/
|
||||
|
||||
#include "codeedit.h"
|
||||
#include "class/qkeysequences.h"
|
||||
#include "class/scriptsettings.h"
|
||||
#include "class/skinmanager.h"
|
||||
#include "control/searchreplacewidget.h"
|
||||
#include "model/codecompletionmodel.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QModelIndex>
|
||||
#include <QScrollBar>
|
||||
#include <QShortcut>
|
||||
|
||||
#include <KSyntaxHighlighting/Definition>
|
||||
|
@ -31,28 +34,49 @@
|
|||
CodeEdit::CodeEdit(QWidget *parent) : WingCodeEdit(parent) {
|
||||
connect(this->document(), &QTextDocument::modificationChanged, this,
|
||||
&CodeEdit::contentModified);
|
||||
addMoveLineShortCut();
|
||||
addEditorBasicShortcut();
|
||||
addMoveLineShortcut();
|
||||
|
||||
connect(&ScriptSettings::instance(), &ScriptSettings::editorSettingsUpdate,
|
||||
this, &CodeEdit::applyEditorSetStyle);
|
||||
applyEditorSetStyle();
|
||||
|
||||
m_searchWidget = new SearchWidget(this, parent);
|
||||
showSearchBar(false);
|
||||
|
||||
m_searchWidget = new SearchReplaceWidget(this);
|
||||
connect(this, &CodeEdit::textChanged, this, [this] {
|
||||
if (m_searchWidget->isVisible())
|
||||
showSearchBar(false);
|
||||
showSearchReplaceBar(false, false);
|
||||
});
|
||||
|
||||
m_gotoWidget = new GotoLineWidget(this);
|
||||
connect(this, &CodeEdit::blockCountChanged, m_gotoWidget,
|
||||
&GotoLineWidget::setTotalLines);
|
||||
connect(m_gotoWidget, &GotoLineWidget::onGotoLine, this, [this](int line) {
|
||||
auto doc = document();
|
||||
auto block = doc->findBlockByNumber(line - 1);
|
||||
|
||||
if (block.isValid()) {
|
||||
QTextCursor cursor(block);
|
||||
cursor.movePosition(QTextCursor::EndOfBlock);
|
||||
setTextCursor(cursor);
|
||||
ensureCursorVisible();
|
||||
}
|
||||
});
|
||||
|
||||
showSearchReplaceBar(false, false);
|
||||
showGotoBar(false);
|
||||
}
|
||||
|
||||
void CodeEdit::showSearchBar(bool show) {
|
||||
void CodeEdit::showSearchReplaceBar(bool show, bool replace) {
|
||||
if (m_gotoWidget->isVisible()) {
|
||||
showGotoBar(false);
|
||||
}
|
||||
m_searchWidget->setVisible(show);
|
||||
m_searchWidget->setEnabled(show);
|
||||
if (show) {
|
||||
const QTextCursor cursor = textCursor();
|
||||
if (cursor.hasSelection())
|
||||
m_searchWidget->setSearchText(cursor.selectedText());
|
||||
m_searchWidget->setReplaceMode(replace);
|
||||
m_searchWidget->activate();
|
||||
} else {
|
||||
clearLiveSearch();
|
||||
|
@ -60,6 +84,15 @@ void CodeEdit::showSearchBar(bool show) {
|
|||
}
|
||||
}
|
||||
|
||||
void CodeEdit::showGotoBar(bool show) {
|
||||
if (m_searchWidget->isVisible()) {
|
||||
showSearchReplaceBar(false, false);
|
||||
}
|
||||
m_gotoWidget->setOriginLine(textCursor().blockNumber() + 1);
|
||||
m_gotoWidget->setVisible(show);
|
||||
m_gotoWidget->setEnabled(show);
|
||||
}
|
||||
|
||||
void CodeEdit::onCompletion(const QModelIndex &index) {
|
||||
WingCodeEdit::onCompletion(index);
|
||||
auto selfdata = index.data(Qt::SelfDataRole).value<CodeInfoTip>();
|
||||
|
@ -75,7 +108,23 @@ void CodeEdit::onCompletion(const QModelIndex &index) {
|
|||
}
|
||||
}
|
||||
|
||||
void CodeEdit::addMoveLineShortCut() {
|
||||
void CodeEdit::addEditorBasicShortcut() {
|
||||
auto find = new QShortcut(QKeySequence(QKeySequence::Find), this);
|
||||
find->setContext(Qt::WidgetShortcut);
|
||||
connect(find, &QShortcut::activated, this,
|
||||
[this]() { showSearchReplaceBar(true, false); });
|
||||
|
||||
auto replace = new QShortcut(QKeySequence(QKeySequence::Replace), this);
|
||||
replace->setContext(Qt::WidgetShortcut);
|
||||
connect(replace, &QShortcut::activated, this,
|
||||
[this]() { showSearchReplaceBar(true, true); });
|
||||
|
||||
auto Goto = new QShortcut(
|
||||
QKeySequences::instance().keySequence(QKeySequences::Key::GOTO), this);
|
||||
connect(Goto, &QShortcut::activated, this, [this]() { showGotoBar(true); });
|
||||
}
|
||||
|
||||
void CodeEdit::addMoveLineShortcut() {
|
||||
auto upLines = new QShortcut(
|
||||
QKeySequence(Qt::ControlModifier | Qt::AltModifier | Qt::Key_Up), this);
|
||||
upLines->setContext(Qt::WidgetShortcut);
|
||||
|
@ -123,15 +172,55 @@ void CodeEdit::applyEditorSetStyle() {
|
|||
this->setAutoCloseChar(set.editorAutoCloseChar());
|
||||
}
|
||||
|
||||
SearchReplaceWidget *CodeEdit::searchWidget() const { return m_searchWidget; }
|
||||
|
||||
void CodeEdit::resizeEvent(QResizeEvent *event) {
|
||||
if (event)
|
||||
WingCodeEdit::resizeEvent(event);
|
||||
|
||||
// Move the search widget to the upper-right corner
|
||||
const QPoint editorPos = this->pos();
|
||||
QSize searchSize = m_searchWidget->sizeHint();
|
||||
m_searchWidget->resize(searchSize);
|
||||
m_searchWidget->move(editorPos.x() + this->viewport()->width() -
|
||||
searchSize.width() - 16,
|
||||
editorPos.y());
|
||||
auto margins = this->contentsMargins();
|
||||
auto off =
|
||||
this->width() - margins.right() - this->verticalScrollBar()->width();
|
||||
auto top = margins.top();
|
||||
|
||||
auto size = m_searchWidget->sizeHint();
|
||||
m_searchWidget->resize(size);
|
||||
m_searchWidget->move(off - size.width(), top);
|
||||
|
||||
size = m_gotoWidget->sizeHint();
|
||||
m_gotoWidget->resize(size);
|
||||
m_gotoWidget->move(off - size.width(), top);
|
||||
}
|
||||
|
||||
void CodeEdit::keyPressEvent(QKeyEvent *event) {
|
||||
bool unHandled = true;
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Escape:
|
||||
if (m_searchWidget->isVisible()) {
|
||||
m_searchWidget->cancel();
|
||||
unHandled = false;
|
||||
}
|
||||
if (m_gotoWidget->isVisible()) {
|
||||
m_gotoWidget->cancel();
|
||||
unHandled = false;
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Enter:
|
||||
if (m_searchWidget->isVisible()) {
|
||||
m_searchWidget->accept();
|
||||
unHandled = false;
|
||||
}
|
||||
if (m_gotoWidget->isVisible()) {
|
||||
m_gotoWidget->accept();
|
||||
unHandled = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (unHandled) {
|
||||
WingCodeEdit::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
#define CODEEDIT_H
|
||||
|
||||
#include "WingCodeEdit/wingcodeedit.h"
|
||||
#include "dialog/searchdialog.h"
|
||||
#include "control/gotolinewidget.h"
|
||||
|
||||
class SearchReplaceWidget;
|
||||
|
||||
class CodeEdit : public WingCodeEdit {
|
||||
Q_OBJECT
|
||||
|
@ -28,7 +30,10 @@ public:
|
|||
explicit CodeEdit(QWidget *parent = nullptr);
|
||||
|
||||
public:
|
||||
void showSearchBar(bool show);
|
||||
void showSearchReplaceBar(bool show, bool replace);
|
||||
void showGotoBar(bool show);
|
||||
|
||||
SearchReplaceWidget *searchWidget() const;
|
||||
|
||||
signals:
|
||||
void contentModified(bool b);
|
||||
|
@ -37,17 +42,20 @@ protected slots:
|
|||
virtual void onCompletion(const QModelIndex &index) override;
|
||||
|
||||
private:
|
||||
void addMoveLineShortCut();
|
||||
void addEditorBasicShortcut();
|
||||
void addMoveLineShortcut();
|
||||
|
||||
// QWidget interface
|
||||
protected:
|
||||
virtual void resizeEvent(QResizeEvent *event) override;
|
||||
virtual void keyPressEvent(QKeyEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void applyEditorSetStyle();
|
||||
|
||||
private:
|
||||
SearchWidget *m_searchWidget;
|
||||
SearchReplaceWidget *m_searchWidget;
|
||||
GotoLineWidget *m_gotoWidget;
|
||||
};
|
||||
|
||||
#endif // CODEEDIT_H
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
#include "codeeditcontrolwidget.h"
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QPainter>
|
||||
|
||||
CodeEditControlWidget::CodeEditControlWidget(QWidget *parent)
|
||||
: QWidget{parent} {}
|
||||
|
||||
QSize CodeEditControlWidget::sizeHint() const {
|
||||
// Make the default just a bit wider
|
||||
const QSize hint = QWidget::sizeHint();
|
||||
return {(hint.width() * 5) / 4, hint.height()};
|
||||
}
|
||||
|
||||
void CodeEditControlWidget::accept() {
|
||||
if (m_defaultButton) {
|
||||
m_defaultButton->animateClick();
|
||||
}
|
||||
}
|
||||
|
||||
void CodeEditControlWidget::cancel() { close(); }
|
||||
|
||||
void CodeEditControlWidget::paintEvent(QPaintEvent *event) {
|
||||
QPainter painter(this);
|
||||
|
||||
// Round the corners of this widget. Not strictly necessary, but
|
||||
// it looks nicer...
|
||||
const int arc = 4;
|
||||
const int circ = 8;
|
||||
const int h = height() - 1;
|
||||
const int w = width() - 1;
|
||||
painter.setPen(palette().color(QPalette::Mid));
|
||||
const QColor windowColor = palette().color(QPalette::Window);
|
||||
painter.setBrush(windowColor);
|
||||
painter.drawEllipse(0, h - circ, circ, circ);
|
||||
painter.drawEllipse(w - circ, h - circ, circ, circ);
|
||||
painter.fillRect(0, 0, arc, h - arc, windowColor);
|
||||
painter.fillRect(w - arc, 0, arc, h - arc, windowColor);
|
||||
painter.fillRect(arc, h - arc, w - circ, arc, windowColor);
|
||||
painter.fillRect(arc, 0, w - circ, h - arc, windowColor);
|
||||
painter.drawLine(0, 0, 0, h - arc);
|
||||
painter.drawLine(arc, h, w - arc, h);
|
||||
painter.drawLine(w, 0, w, h - arc);
|
||||
}
|
||||
|
||||
void CodeEditControlWidget::keyPressEvent(QKeyEvent *event) {
|
||||
if (event->key() == Qt::Key_Escape) {
|
||||
cancel();
|
||||
} else if (event->key() == Qt::Key_Enter) {
|
||||
accept();
|
||||
} else {
|
||||
QWidget::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
QAbstractButton *CodeEditControlWidget::defaultButton() const {
|
||||
return m_defaultButton;
|
||||
}
|
||||
|
||||
void CodeEditControlWidget::setDefaultButton(
|
||||
QAbstractButton *newDefaultButton) {
|
||||
m_defaultButton = newDefaultButton;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef CODEEDITCONTROLWIDGET_H
|
||||
#define CODEEDITCONTROLWIDGET_H
|
||||
|
||||
#include <QAbstractButton>
|
||||
#include <QWidget>
|
||||
|
||||
class CodeEditControlWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CodeEditControlWidget(QWidget *parent = nullptr);
|
||||
|
||||
public:
|
||||
virtual QSize sizeHint() const override;
|
||||
virtual void accept();
|
||||
virtual void cancel();
|
||||
|
||||
QAbstractButton *defaultButton() const;
|
||||
void setDefaultButton(QAbstractButton *newDefaultButton);
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent *event) override;
|
||||
virtual void keyPressEvent(QKeyEvent *event) override;
|
||||
|
||||
private:
|
||||
QAbstractButton *m_defaultButton = nullptr;
|
||||
};
|
||||
|
||||
#endif // CODEEDITCONTROLWIDGET_H
|
|
@ -0,0 +1,74 @@
|
|||
/*==============================================================================
|
||||
** Copyright (C) 2024-2027 WingSummer
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify it under
|
||||
** the terms of the GNU Affero General Public License as published by the Free
|
||||
** Software Foundation, version 3.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
** details.
|
||||
**
|
||||
** You should have received a copy of the GNU Affero General Public License
|
||||
** along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
** =============================================================================
|
||||
*/
|
||||
|
||||
#include "gotolinewidget.h"
|
||||
|
||||
#include "class/skinmanager.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QToolButton>
|
||||
|
||||
GotoLineWidget::GotoLineWidget(QWidget *parent)
|
||||
: CodeEditControlWidget(parent) {
|
||||
auto &skin = SkinManager::instance();
|
||||
|
||||
auto closeBtn = new QToolButton(this);
|
||||
closeBtn->setIcon(skin.themeIcon(QStringLiteral("dialog_close")));
|
||||
closeBtn->setToolTip(tr("Close"));
|
||||
closeBtn->setIconSize(QSize(12, 12));
|
||||
closeBtn->setStyleSheet(QStringLiteral("border:none;"));
|
||||
connect(closeBtn, &QToolButton::clicked, this, &GotoLineWidget::close);
|
||||
|
||||
m_sbline = new QSpinBox(this);
|
||||
m_sbline->setRange(1, 1);
|
||||
m_sbline->setMinimumWidth(120);
|
||||
connect(m_sbline, &QSpinBox::valueChanged, this,
|
||||
&GotoLineWidget::onGotoLine);
|
||||
|
||||
auto tbGoto = new QToolButton(this);
|
||||
tbGoto->setAutoRaise(true);
|
||||
tbGoto->setIcon(skin.themeIcon(QStringLiteral("right_arrow")));
|
||||
connect(tbGoto, &QToolButton::clicked, this, [this]() {
|
||||
emit onGotoLine(m_sbline->value());
|
||||
close();
|
||||
});
|
||||
|
||||
auto layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(5, 5, 5, 5);
|
||||
layout->setSpacing(5);
|
||||
layout->addWidget(closeBtn);
|
||||
layout->addWidget(m_sbline, 1);
|
||||
layout->addWidget(tbGoto);
|
||||
|
||||
setLayout(layout);
|
||||
setDefaultButton(tbGoto);
|
||||
}
|
||||
|
||||
void GotoLineWidget::setTotalLines(int lineTotal) {
|
||||
m_sbline->setMaximum(lineTotal);
|
||||
}
|
||||
|
||||
void GotoLineWidget::setOriginLine(int line) {
|
||||
m_sbline->setValue(line);
|
||||
m_line = m_sbline->value();
|
||||
}
|
||||
|
||||
void GotoLineWidget::cancel() {
|
||||
emit onGotoLine(m_line);
|
||||
CodeEditControlWidget::cancel();
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*==============================================================================
|
||||
** Copyright (C) 2024-2027 WingSummer
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify it under
|
||||
** the terms of the GNU Affero General Public License as published by the Free
|
||||
** Software Foundation, version 3.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
** details.
|
||||
**
|
||||
** You should have received a copy of the GNU Affero General Public License
|
||||
** along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
** =============================================================================
|
||||
*/
|
||||
|
||||
#ifndef GOTOLINEWIDGET_H
|
||||
#define GOTOLINEWIDGET_H
|
||||
|
||||
#include "control/codeeditcontrolwidget.h"
|
||||
|
||||
#include <QSpinBox>
|
||||
|
||||
class GotoLineWidget : public CodeEditControlWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit GotoLineWidget(QWidget *parent = nullptr);
|
||||
|
||||
void setTotalLines(int lineTotal);
|
||||
|
||||
signals:
|
||||
void onGotoLine(int line);
|
||||
|
||||
public:
|
||||
void setOriginLine(int line);
|
||||
|
||||
// CodeEditControlWidget interface
|
||||
public:
|
||||
virtual void cancel() override;
|
||||
|
||||
private:
|
||||
QSpinBox *m_sbline;
|
||||
int m_line = 1;
|
||||
};
|
||||
|
||||
#endif // GOTOLINEWIDGET_H
|
|
@ -131,6 +131,12 @@ bool ScriptEditor::save(const QString &path) {
|
|||
|
||||
bool ScriptEditor::reload() { return openFile(m_fileName); }
|
||||
|
||||
void ScriptEditor::find() { m_editor->showSearchReplaceBar(true, false); }
|
||||
|
||||
void ScriptEditor::replace() { m_editor->showSearchReplaceBar(true, true); }
|
||||
|
||||
void ScriptEditor::gotoLine() { m_editor->showGotoBar(true); }
|
||||
|
||||
void ScriptEditor::setReadOnly(bool b) {
|
||||
m_editor->setReadOnly(b);
|
||||
this->tabWidget()->setIcon(b ? ICONRES("lockon") : QIcon());
|
||||
|
|
|
@ -41,12 +41,15 @@ signals:
|
|||
void onFunctionTip(const QString &tip);
|
||||
|
||||
public slots:
|
||||
void setReadOnly(bool b);
|
||||
bool openFile(const QString &filename);
|
||||
|
||||
bool save(const QString &path = QString());
|
||||
bool reload();
|
||||
|
||||
void setReadOnly(bool b);
|
||||
void find();
|
||||
void replace();
|
||||
void gotoLine();
|
||||
|
||||
private:
|
||||
void processTitle();
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
** =============================================================================
|
||||
*/
|
||||
|
||||
#include "searchdialog.h"
|
||||
#include "utilities.h"
|
||||
#include "searchreplacewidget.h"
|
||||
|
||||
#include "class/skinmanager.h"
|
||||
#include "class/wingmessagebox.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
|
@ -40,288 +40,6 @@
|
|||
#include <QStyleHints>
|
||||
#endif
|
||||
|
||||
static SearchDialog *s_instance = Q_NULLPTR;
|
||||
|
||||
SearchWidget::SearchWidget(WingCodeEdit *editor, QWidget *parent)
|
||||
: QWidget(parent), m_editor(editor) {
|
||||
|
||||
auto tbMenu = new QToolButton(this);
|
||||
tbMenu->setAutoRaise(true);
|
||||
tbMenu->setIcon(QIcon::fromTheme(QStringLiteral("theme")));
|
||||
tbMenu->setToolTip(tr("Search Settings"));
|
||||
tbMenu->setStyleSheet(
|
||||
QStringLiteral("QToolButton::menu-indicator { image: none; }"));
|
||||
|
||||
auto settingsMenu = new QMenu(this);
|
||||
m_caseSensitive = settingsMenu->addAction(tr("Match ca&se"));
|
||||
m_caseSensitive->setCheckable(true);
|
||||
m_wholeWord = settingsMenu->addAction(tr("Match &whole words"));
|
||||
m_wholeWord->setCheckable(true);
|
||||
m_regex = settingsMenu->addAction(tr("Regular e&xpressions"));
|
||||
m_regex->setCheckable(true);
|
||||
m_escapes = settingsMenu->addAction(tr("&Escape sequences"));
|
||||
m_escapes->setCheckable(true);
|
||||
m_wrapSearch = settingsMenu->addAction(tr("Wrap Aro&und"));
|
||||
m_wrapSearch->setCheckable(true);
|
||||
tbMenu->setMenu(settingsMenu);
|
||||
tbMenu->setPopupMode(QToolButton::InstantPopup);
|
||||
|
||||
connect(m_caseSensitive, &QAction::triggered, this,
|
||||
&SearchWidget::updateSettings);
|
||||
connect(m_wholeWord, &QAction::triggered, this,
|
||||
&SearchWidget::updateSettings);
|
||||
connect(m_regex, &QAction::triggered, this, &SearchWidget::updateSettings);
|
||||
connect(m_escapes, &QAction::triggered, this,
|
||||
&SearchWidget::updateSettings);
|
||||
connect(m_wrapSearch, &QAction::triggered, this,
|
||||
&SearchWidget::updateSettings);
|
||||
|
||||
m_searchText = new QLineEdit(this);
|
||||
m_searchText->setClearButtonEnabled(true);
|
||||
setFocusProxy(m_searchText);
|
||||
|
||||
auto tbNext = new QToolButton(this);
|
||||
tbNext->setAutoRaise(true);
|
||||
tbNext->setIcon(ICONRES(""));
|
||||
tbNext->setToolTip(tr("Find Next"));
|
||||
|
||||
auto tbPrev = new QToolButton(this);
|
||||
tbPrev->setAutoRaise(true);
|
||||
tbPrev->setIcon(ICONRES(""));
|
||||
tbPrev->setToolTip(tr("Find Previous"));
|
||||
|
||||
auto layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(5, 5, 5, 5);
|
||||
layout->setSpacing(5);
|
||||
layout->addWidget(tbMenu);
|
||||
layout->addWidget(m_searchText);
|
||||
layout->addWidget(tbNext);
|
||||
layout->addWidget(tbPrev);
|
||||
setLayout(layout);
|
||||
|
||||
connect(m_searchText, &QLineEdit::textChanged, this,
|
||||
[this](const QString &text) {
|
||||
m_searchParams.searchText =
|
||||
m_escapes->isChecked()
|
||||
? SearchDialog::translateEscapes(text)
|
||||
: text;
|
||||
m_editor->setLiveSearch(m_searchParams);
|
||||
});
|
||||
connect(m_searchText, &QLineEdit::returnPressed, this,
|
||||
[this] { searchNext(false); });
|
||||
connect(tbNext, &QToolButton::clicked, this, [this] { searchNext(false); });
|
||||
connect(tbPrev, &QToolButton::clicked, this, [this] { searchNext(true); });
|
||||
}
|
||||
|
||||
void SearchWidget::setSearchText(const QString &text) {
|
||||
m_searchText->setText(text);
|
||||
}
|
||||
|
||||
void SearchWidget::activate() {
|
||||
m_searchParams.caseSensitive = m_caseSensitive->isChecked();
|
||||
m_searchParams.wholeWord = m_wholeWord->isChecked();
|
||||
m_searchParams.regex = m_regex->isChecked();
|
||||
|
||||
setFocus(Qt::OtherFocusReason);
|
||||
m_searchText->selectAll();
|
||||
m_editor->setLiveSearch(m_searchParams);
|
||||
}
|
||||
|
||||
void SearchWidget::searchNext(bool reverse) {
|
||||
if (!isVisible()) {
|
||||
setVisible(true);
|
||||
setEnabled(true);
|
||||
activate();
|
||||
}
|
||||
if (m_searchParams.searchText.isEmpty())
|
||||
return;
|
||||
|
||||
auto searchCursor = m_editor->textSearch(m_editor->textCursor(),
|
||||
m_searchParams, false, reverse);
|
||||
if (searchCursor.isNull() && m_wrapSearch->isChecked()) {
|
||||
QTextCursor wrapCursor = m_editor->textCursor();
|
||||
wrapCursor.movePosition(reverse ? QTextCursor::End
|
||||
: QTextCursor::Start);
|
||||
searchCursor =
|
||||
m_editor->textSearch(wrapCursor, m_searchParams, true, reverse);
|
||||
}
|
||||
|
||||
if (searchCursor.isNull())
|
||||
QMessageBox::information(this, QString(),
|
||||
tr("The specified text was not found"));
|
||||
else
|
||||
m_editor->setTextCursor(searchCursor);
|
||||
}
|
||||
|
||||
void SearchWidget::paintEvent(QPaintEvent *) {
|
||||
QPainter painter(this);
|
||||
|
||||
// Round the corners of this widget. Not strictly necessary, but
|
||||
// it looks nicer...
|
||||
const int arc = 4;
|
||||
const int circ = 8;
|
||||
const int h = height() - 1;
|
||||
const int w = width() - 1;
|
||||
painter.setPen(palette().color(QPalette::Mid));
|
||||
const QColor windowColor = palette().color(QPalette::Window);
|
||||
painter.setBrush(windowColor);
|
||||
painter.drawEllipse(0, h - circ, circ, circ);
|
||||
painter.drawEllipse(w - circ, h - circ, circ, circ);
|
||||
painter.fillRect(0, 0, arc, h - arc, windowColor);
|
||||
painter.fillRect(w - arc, 0, arc, h - arc, windowColor);
|
||||
painter.fillRect(arc, h - arc, w - circ, arc, windowColor);
|
||||
painter.fillRect(arc, 0, w - circ, h - arc, windowColor);
|
||||
painter.drawLine(0, 0, 0, h - arc);
|
||||
painter.drawLine(arc, h, w - arc, h);
|
||||
painter.drawLine(w, 0, w, h - arc);
|
||||
}
|
||||
|
||||
void SearchWidget::updateSettings() {
|
||||
m_searchParams.caseSensitive = m_caseSensitive->isChecked();
|
||||
m_searchParams.wholeWord = m_wholeWord->isChecked();
|
||||
m_searchParams.regex = m_regex->isChecked();
|
||||
|
||||
m_editor->setLiveSearch(m_searchParams);
|
||||
}
|
||||
|
||||
/* Just sets some more sane defaults for QComboBox:
|
||||
* - Don't auto-insert items (we handle that manually)
|
||||
* - Disable the completer, since it insists on changing the typed
|
||||
* item to match another item in the list that differs only in case.
|
||||
*/
|
||||
class SearchComboBox : public QComboBox {
|
||||
public:
|
||||
explicit SearchComboBox(QWidget *parent) : QComboBox(parent) {
|
||||
setEditable(true);
|
||||
setInsertPolicy(QComboBox::NoInsert);
|
||||
setDuplicatesEnabled(true);
|
||||
setCompleter(Q_NULLPTR);
|
||||
}
|
||||
};
|
||||
|
||||
SearchDialog::SearchDialog(QWidget *parent)
|
||||
: FramelessDialogBase(parent), m_editor() {
|
||||
s_instance = this;
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
setWindowTitle(tr("Find and Replace..."));
|
||||
setWindowIcon(ICONRES("edit-find-replace"));
|
||||
|
||||
m_searchText = new SearchComboBox(this);
|
||||
m_replaceText = new SearchComboBox(this);
|
||||
|
||||
m_caseSensitive = new QCheckBox(tr("Match ca&se"), this);
|
||||
m_caseSensitive->setChecked(false);
|
||||
m_wholeWord = new QCheckBox(tr("Match &whole words"), this);
|
||||
m_wholeWord->setChecked(false);
|
||||
m_regex = new QCheckBox(tr("Regular e&xpressions"), this);
|
||||
m_regex->setChecked(false);
|
||||
m_escapes = new QCheckBox(tr("&Escape sequences"), this);
|
||||
m_escapes->setChecked(false);
|
||||
m_wrapSearch = new QCheckBox(tr("Wrap Aro&und"), this);
|
||||
m_wrapSearch->setChecked(false);
|
||||
|
||||
// QDialogButtonBox insists on rearranging buttons depending on your
|
||||
// platform, which would be fine if we only had standard actions, but most
|
||||
// of our action buttons here are custom.
|
||||
auto buttonBox = new QWidget(this);
|
||||
buttonBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding);
|
||||
auto buttonLayout = new QVBoxLayout(buttonBox);
|
||||
buttonLayout->setContentsMargins(0, 0, 0, 0);
|
||||
buttonLayout->setSpacing(5);
|
||||
auto findNext = new QPushButton(tr("Find &Next"), this);
|
||||
buttonLayout->addWidget(findNext);
|
||||
auto findPrev = new QPushButton(tr("Find &Previous"), this);
|
||||
buttonLayout->addWidget(findPrev);
|
||||
auto replaceNext = new QPushButton(tr("&Replace"), this);
|
||||
buttonLayout->addWidget(replaceNext);
|
||||
auto replaceAll = new QPushButton(tr("Replace &All"), this);
|
||||
buttonLayout->addWidget(replaceAll);
|
||||
m_replaceSelectionButton = new QPushButton(tr("&In Selection"), this);
|
||||
buttonLayout->addWidget(m_replaceSelectionButton);
|
||||
buttonLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum,
|
||||
QSizePolicy::MinimumExpanding));
|
||||
auto closeButton = new QPushButton(tr("&Close"), this);
|
||||
buttonLayout->addWidget(closeButton);
|
||||
|
||||
connect(findNext, &QPushButton::clicked, this,
|
||||
&SearchDialog::searchForward);
|
||||
connect(findPrev, &QPushButton::clicked, this,
|
||||
&SearchDialog::searchBackward);
|
||||
connect(replaceNext, &QPushButton::clicked, this,
|
||||
&SearchDialog::replaceCurrent);
|
||||
connect(replaceAll, &QPushButton::clicked, this,
|
||||
[this] { performReplaceAll(WholeDocument); });
|
||||
connect(m_replaceSelectionButton, &QPushButton::clicked, this,
|
||||
[this] { performReplaceAll(InSelection); });
|
||||
connect(closeButton, &QPushButton::clicked, this, &QDialog::close);
|
||||
|
||||
auto w = new QWidget(this);
|
||||
auto layout = new QGridLayout(w);
|
||||
layout->setContentsMargins(10, 10, 10, 10);
|
||||
layout->setVerticalSpacing(5);
|
||||
layout->setHorizontalSpacing(10);
|
||||
auto searchLabel = new QLabel(tr("&Find:"), this);
|
||||
searchLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||
searchLabel->setBuddy(m_searchText);
|
||||
layout->addWidget(searchLabel, 0, 0);
|
||||
layout->addWidget(m_searchText, 0, 1, 1, 2);
|
||||
auto replaceLabel = new QLabel(tr("Replace wit&h:"), this);
|
||||
replaceLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||
replaceLabel->setBuddy(m_replaceText);
|
||||
layout->addWidget(replaceLabel, 1, 0);
|
||||
layout->addWidget(m_replaceText, 1, 1, 1, 2);
|
||||
layout->addItem(new QSpacerItem(0, 10, QSizePolicy::MinimumExpanding,
|
||||
QSizePolicy::Fixed),
|
||||
2, 0, 1, 3);
|
||||
layout->addWidget(m_caseSensitive, 3, 1);
|
||||
layout->addWidget(m_wholeWord, 4, 1);
|
||||
layout->addWidget(m_regex, 5, 1);
|
||||
layout->addWidget(m_escapes, 6, 1);
|
||||
layout->addWidget(m_wrapSearch, 3, 2);
|
||||
layout->addItem(
|
||||
new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding),
|
||||
layout->rowCount(), 0, 1, 3);
|
||||
layout->addWidget(buttonBox, 0, layout->columnCount(), layout->rowCount(),
|
||||
1);
|
||||
buildUpContent(w);
|
||||
}
|
||||
|
||||
SearchDialog::~SearchDialog() {
|
||||
syncSearchSettings(false);
|
||||
s_instance = Q_NULLPTR;
|
||||
}
|
||||
|
||||
SearchDialog *SearchDialog::create(WingCodeEdit *editor, QWidget *parent) {
|
||||
if (s_instance) {
|
||||
s_instance->raise();
|
||||
} else {
|
||||
Q_ASSERT(parent);
|
||||
s_instance = new SearchDialog(parent);
|
||||
s_instance->show();
|
||||
s_instance->raise();
|
||||
s_instance->activateWindow();
|
||||
|
||||
s_instance->m_editor = editor;
|
||||
connect(s_instance->m_editor, &WingCodeEdit::selectionChanged,
|
||||
s_instance, [] {
|
||||
bool hasSelection =
|
||||
s_instance->m_editor->textCursor().hasSelection();
|
||||
s_instance->m_replaceSelectionButton->setEnabled(
|
||||
hasSelection);
|
||||
});
|
||||
}
|
||||
|
||||
const QTextCursor cursor = s_instance->m_editor->textCursor();
|
||||
if (cursor.hasSelection()) {
|
||||
s_instance->m_searchText->setCurrentText(cursor.selectedText());
|
||||
s_instance->m_searchText->lineEdit()->selectAll();
|
||||
}
|
||||
s_instance->m_replaceSelectionButton->setEnabled(cursor.hasSelection());
|
||||
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
static QString translateCharEscape(QStringView digits, int *advance) {
|
||||
Q_ASSERT(digits.size() > 0);
|
||||
Q_ASSERT(advance);
|
||||
|
@ -374,7 +92,7 @@ static QString translateCharEscape(QStringView digits, int *advance) {
|
|||
}
|
||||
}
|
||||
|
||||
QString SearchDialog::translateEscapes(const QString &text) {
|
||||
QString translateEscapes(const QString &text) {
|
||||
QString result;
|
||||
result.reserve(text.size());
|
||||
int start = 0;
|
||||
|
@ -445,8 +163,287 @@ QString SearchDialog::translateEscapes(const QString &text) {
|
|||
return result;
|
||||
}
|
||||
|
||||
QString SearchDialog::regexReplace(const QString &text,
|
||||
const QRegularExpressionMatch ®exMatch) {
|
||||
SearchReplaceWidget::SearchReplaceWidget(CodeEdit *editor)
|
||||
: CodeEditControlWidget(editor), m_editor(editor) {
|
||||
auto &skin = SkinManager::instance();
|
||||
|
||||
auto closeBtn = new QToolButton(this);
|
||||
closeBtn->setIcon(skin.themeIcon(QStringLiteral("dialog_close")));
|
||||
closeBtn->setToolTip(tr("Close"));
|
||||
closeBtn->setIconSize(QSize(12, 12));
|
||||
closeBtn->setStyleSheet(QStringLiteral("border:none;"));
|
||||
connect(closeBtn, &QToolButton::clicked, this,
|
||||
&SearchReplaceWidget::cancel);
|
||||
|
||||
auto tbMenu = new QToolButton(this);
|
||||
tbMenu->setAutoRaise(true);
|
||||
tbMenu->setIcon(skin.themeIcon(QStringLiteral("menu")));
|
||||
tbMenu->setToolTip(tr("Search Settings"));
|
||||
tbMenu->setStyleSheet(
|
||||
QStringLiteral("QToolButton::menu-indicator { image: none; }"));
|
||||
|
||||
auto settingsMenu = new QMenu(this);
|
||||
m_caseSensitive = settingsMenu->addAction(tr("Match ca&se"));
|
||||
m_caseSensitive->setCheckable(true);
|
||||
m_wholeWord = settingsMenu->addAction(tr("Match &whole words"));
|
||||
m_wholeWord->setCheckable(true);
|
||||
m_regex = settingsMenu->addAction(tr("Regular e&xpressions"));
|
||||
m_regex->setCheckable(true);
|
||||
m_escapes = settingsMenu->addAction(tr("&Escape sequences"));
|
||||
m_escapes->setCheckable(true);
|
||||
m_wrapSearch = settingsMenu->addAction(tr("Wrap Aro&und"));
|
||||
m_wrapSearch->setCheckable(true);
|
||||
m_wrapSearch->setChecked(true);
|
||||
m_replaceSel = settingsMenu->addAction(tr("Replace in selection"));
|
||||
m_replaceSel->setCheckable(true);
|
||||
tbMenu->setMenu(settingsMenu);
|
||||
tbMenu->setPopupMode(QToolButton::InstantPopup);
|
||||
|
||||
connect(m_caseSensitive, &QAction::triggered, this,
|
||||
&SearchReplaceWidget::updateSettings);
|
||||
connect(m_wholeWord, &QAction::triggered, this,
|
||||
&SearchReplaceWidget::updateSettings);
|
||||
connect(m_regex, &QAction::triggered, this,
|
||||
&SearchReplaceWidget::updateSettings);
|
||||
connect(m_escapes, &QAction::triggered, this,
|
||||
&SearchReplaceWidget::updateSettings);
|
||||
connect(m_wrapSearch, &QAction::triggered, this,
|
||||
&SearchReplaceWidget::updateSettings);
|
||||
|
||||
m_searchText = new QLineEdit(this);
|
||||
m_searchText->setClearButtonEnabled(true);
|
||||
setFocusProxy(m_searchText);
|
||||
|
||||
auto tbNext = new QToolButton(this);
|
||||
tbNext->setAutoRaise(true);
|
||||
tbNext->setIcon(skin.themeIcon(QStringLiteral("right_arrow")));
|
||||
tbNext->setToolTip(tr("Find Next"));
|
||||
|
||||
auto tbPrev = new QToolButton(this);
|
||||
tbPrev->setAutoRaise(true);
|
||||
tbPrev->setIcon(skin.themeIcon(QStringLiteral("left_arrow")));
|
||||
tbPrev->setToolTip(tr("Find Previous"));
|
||||
|
||||
auto mlayout = new QVBoxLayout(this);
|
||||
mlayout->setContentsMargins(5, 5, 5, 5);
|
||||
mlayout->setSpacing(3);
|
||||
|
||||
m_replaceText = new QLineEdit(this);
|
||||
m_replaceText->setClearButtonEnabled(true);
|
||||
|
||||
auto tbReplaceCur = new QToolButton(this);
|
||||
tbReplaceCur->setAutoRaise(true);
|
||||
tbReplaceCur->setIcon(skin.themeIcon(QStringLiteral("dialog_apply")));
|
||||
tbReplaceCur->setToolTip(tr("Replace Current"));
|
||||
|
||||
auto tbReplaceAll = new QToolButton(this);
|
||||
tbReplaceAll->setAutoRaise(true);
|
||||
tbReplaceAll->setIcon(skin.themeIcon(QStringLiteral("dialog_yes_to_all")));
|
||||
tbReplaceAll->setToolTip(tr("Replace All"));
|
||||
|
||||
auto layout = new QHBoxLayout;
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(5);
|
||||
layout->addWidget(closeBtn);
|
||||
layout->addWidget(tbMenu);
|
||||
layout->addWidget(m_searchText);
|
||||
layout->addWidget(tbPrev);
|
||||
layout->addWidget(tbNext);
|
||||
mlayout->addLayout(layout);
|
||||
|
||||
m_replaceWidgets = new QWidget(this);
|
||||
layout = new QHBoxLayout(m_replaceWidgets);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(5);
|
||||
layout->addWidget(new QLabel(tr("Replace:"), this));
|
||||
layout->addWidget(m_replaceText);
|
||||
layout->addWidget(tbReplaceCur);
|
||||
layout->addWidget(tbReplaceAll);
|
||||
|
||||
mlayout->addWidget(m_replaceWidgets);
|
||||
setLayout(mlayout);
|
||||
|
||||
connect(m_searchText, &QLineEdit::textChanged, this,
|
||||
[this](const QString &text) {
|
||||
m_searchParams.searchText =
|
||||
m_escapes->isChecked() ? translateEscapes(text) : text;
|
||||
m_editor->setLiveSearch(m_searchParams);
|
||||
});
|
||||
connect(m_searchText, &QLineEdit::returnPressed, this,
|
||||
&SearchReplaceWidget::searchForward);
|
||||
connect(tbNext, &QToolButton::clicked, this,
|
||||
&SearchReplaceWidget::searchForward);
|
||||
connect(tbPrev, &QToolButton::clicked, this,
|
||||
&SearchReplaceWidget::searchBackward);
|
||||
connect(tbReplaceCur, &QToolButton::clicked, this,
|
||||
&SearchReplaceWidget::replaceCurrent);
|
||||
connect(tbReplaceAll, &QToolButton::clicked, this, [this]() {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
void SearchReplaceWidget::setSearchText(const QString &text) {
|
||||
m_searchText->setText(text);
|
||||
}
|
||||
|
||||
void SearchReplaceWidget::setReplaceMode(bool b) {
|
||||
m_replaceWidgets->setVisible(b);
|
||||
m_replaceWidgets->setEnabled(b);
|
||||
m_replaceSel->setVisible(b);
|
||||
m_replaceSel->setEnabled(b);
|
||||
}
|
||||
|
||||
void SearchReplaceWidget::activate() {
|
||||
resize(sizeHint()); // readjust size (height)
|
||||
|
||||
m_searchParams.caseSensitive = m_caseSensitive->isChecked();
|
||||
m_searchParams.wholeWord = m_wholeWord->isChecked();
|
||||
m_searchParams.regex = m_regex->isChecked();
|
||||
|
||||
setFocus(Qt::OtherFocusReason);
|
||||
m_searchText->selectAll();
|
||||
m_editor->setLiveSearch(m_searchParams);
|
||||
}
|
||||
|
||||
void SearchReplaceWidget::cancel() {
|
||||
m_editor->clearLiveSearch();
|
||||
CodeEditControlWidget::cancel();
|
||||
}
|
||||
|
||||
void SearchReplaceWidget::searchForward() {
|
||||
updateSettings();
|
||||
m_replaceCursor = searchNext(false);
|
||||
}
|
||||
|
||||
void SearchReplaceWidget::searchBackward() {
|
||||
updateSettings();
|
||||
m_replaceCursor = searchNext(true);
|
||||
}
|
||||
|
||||
void SearchReplaceWidget::replaceCurrent() {
|
||||
updateSettings();
|
||||
Q_ASSERT(m_editor);
|
||||
|
||||
const QString searchText = m_searchText->text();
|
||||
if (searchText.isEmpty())
|
||||
return;
|
||||
|
||||
if (m_replaceCursor.isNull() || m_replaceCursor != m_editor->textCursor()) {
|
||||
m_replaceCursor = searchNext(false);
|
||||
return;
|
||||
}
|
||||
|
||||
QString replaceText = m_replaceText->text();
|
||||
if (m_escapes->isChecked())
|
||||
replaceText = translateEscapes(replaceText);
|
||||
|
||||
m_replaceCursor.beginEditBlock();
|
||||
m_replaceCursor.removeSelectedText();
|
||||
if (m_regex->isChecked())
|
||||
m_replaceCursor.insertText(regexReplace(replaceText, m_regexMatch));
|
||||
else
|
||||
m_replaceCursor.insertText(replaceText);
|
||||
m_replaceCursor.endEditBlock();
|
||||
|
||||
m_replaceCursor = searchNext(false);
|
||||
}
|
||||
|
||||
void SearchReplaceWidget::performReplaceAll(ReplaceAllMode mode) {
|
||||
updateSettings();
|
||||
Q_ASSERT(m_editor);
|
||||
|
||||
const QString searchText = m_searchText->text();
|
||||
if (searchText.isEmpty())
|
||||
return;
|
||||
|
||||
auto searchCursor = m_editor->textCursor();
|
||||
if (mode == InSelection)
|
||||
searchCursor.setPosition(m_editor->textCursor().selectionStart());
|
||||
else
|
||||
searchCursor.movePosition(QTextCursor::Start);
|
||||
searchCursor = m_editor->textSearch(searchCursor, m_searchParams, true,
|
||||
false, &m_regexMatch);
|
||||
if (searchCursor.isNull()) {
|
||||
QMessageBox::information(this, QString(),
|
||||
tr("The specified text was not found"));
|
||||
return;
|
||||
} else if (mode == InSelection &&
|
||||
searchCursor.selectionEnd() >
|
||||
m_editor->textCursor().selectionEnd()) {
|
||||
WingMessageBox::information(
|
||||
this, QString(),
|
||||
tr("The specified text was not found in the selection"));
|
||||
return;
|
||||
}
|
||||
|
||||
QString replaceText = m_replaceText->text();
|
||||
if (m_escapes->isChecked())
|
||||
replaceText = translateEscapes(replaceText);
|
||||
|
||||
searchCursor.beginEditBlock();
|
||||
auto replaceCursor = searchCursor;
|
||||
int replacements = 0;
|
||||
while (!replaceCursor.isNull()) {
|
||||
if (mode == InSelection && replaceCursor.selectionEnd() >
|
||||
m_editor->textCursor().selectionEnd())
|
||||
break;
|
||||
|
||||
replaceCursor.removeSelectedText();
|
||||
if (m_regex->isChecked())
|
||||
replaceCursor.insertText(regexReplace(replaceText, m_regexMatch));
|
||||
else
|
||||
replaceCursor.insertText(replaceText);
|
||||
replaceCursor = m_editor->textSearch(replaceCursor, m_searchParams,
|
||||
false, false, &m_regexMatch);
|
||||
++replacements;
|
||||
}
|
||||
searchCursor.endEditBlock();
|
||||
|
||||
WingMessageBox::information(
|
||||
this, QString(),
|
||||
tr("Successfully replaced %1 matches").arg(replacements));
|
||||
}
|
||||
|
||||
QTextCursor SearchReplaceWidget::searchNext(bool reverse) {
|
||||
if (!isVisible()) {
|
||||
setVisible(true);
|
||||
setEnabled(true);
|
||||
activate();
|
||||
}
|
||||
Q_ASSERT(m_editor);
|
||||
|
||||
if (m_searchParams.searchText.isEmpty())
|
||||
return QTextCursor();
|
||||
|
||||
auto searchCursor = m_editor->textSearch(
|
||||
m_editor->textCursor(), m_searchParams, false, reverse, &m_regexMatch);
|
||||
if (searchCursor.isNull() && m_wrapSearch->isChecked()) {
|
||||
QTextCursor wrapCursor = m_editor->textCursor();
|
||||
wrapCursor.movePosition(reverse ? QTextCursor::End
|
||||
: QTextCursor::Start);
|
||||
searchCursor = m_editor->textSearch(wrapCursor, m_searchParams, true,
|
||||
reverse, &m_regexMatch);
|
||||
}
|
||||
|
||||
if (searchCursor.isNull())
|
||||
WingMessageBox::information(this, QString(),
|
||||
tr("The specified text was not found"));
|
||||
else
|
||||
m_editor->setTextCursor(searchCursor);
|
||||
return searchCursor;
|
||||
}
|
||||
|
||||
void SearchReplaceWidget::updateSettings() {
|
||||
m_searchParams.caseSensitive = m_caseSensitive->isChecked();
|
||||
m_searchParams.wholeWord = m_wholeWord->isChecked();
|
||||
m_searchParams.regex = m_regex->isChecked();
|
||||
|
||||
m_editor->setLiveSearch(m_searchParams);
|
||||
}
|
||||
|
||||
QString
|
||||
SearchReplaceWidget::regexReplace(const QString &text,
|
||||
const QRegularExpressionMatch ®exMatch) {
|
||||
QString result;
|
||||
result.reserve(text.size());
|
||||
int start = 0;
|
||||
|
@ -474,145 +471,3 @@ QString SearchDialog::regexReplace(const QString &text,
|
|||
result.append(text.sliced(start));
|
||||
return result;
|
||||
}
|
||||
|
||||
void SearchDialog::syncSearchSettings(bool saveRecent) {
|
||||
const QString searchText = m_searchText->currentText();
|
||||
if (!searchText.isEmpty() && saveRecent) {
|
||||
if (m_searchText->count() == 0 ||
|
||||
m_searchText->itemText(0) != searchText) {
|
||||
m_searchText->insertItem(0, searchText);
|
||||
}
|
||||
}
|
||||
m_searchParams.searchText =
|
||||
m_escapes->isChecked() ? translateEscapes(searchText) : searchText;
|
||||
|
||||
const QString replaceText = m_replaceText->currentText();
|
||||
if (!replaceText.isEmpty() && saveRecent) {
|
||||
if (m_replaceText->count() == 0 ||
|
||||
m_replaceText->itemText(0) != replaceText) {
|
||||
m_replaceText->insertItem(0, replaceText);
|
||||
}
|
||||
}
|
||||
|
||||
m_searchParams.caseSensitive = m_caseSensitive->isChecked();
|
||||
m_searchParams.wholeWord = m_wholeWord->isChecked();
|
||||
m_searchParams.regex = m_regex->isChecked();
|
||||
}
|
||||
|
||||
QTextCursor SearchDialog::searchNext(bool reverse) {
|
||||
Q_ASSERT(m_editor);
|
||||
|
||||
if (m_searchParams.searchText.isEmpty())
|
||||
return QTextCursor();
|
||||
|
||||
auto searchCursor = m_editor->textSearch(
|
||||
m_editor->textCursor(), m_searchParams, false, reverse, &m_regexMatch);
|
||||
if (searchCursor.isNull() && m_wrapSearch->isChecked()) {
|
||||
QTextCursor wrapCursor = m_editor->textCursor();
|
||||
wrapCursor.movePosition(reverse ? QTextCursor::End
|
||||
: QTextCursor::Start);
|
||||
searchCursor = m_editor->textSearch(wrapCursor, m_searchParams, true,
|
||||
reverse, &m_regexMatch);
|
||||
}
|
||||
|
||||
if (searchCursor.isNull())
|
||||
WingMessageBox::information(this, QString(),
|
||||
tr("The specified text was not found"));
|
||||
else
|
||||
m_editor->setTextCursor(searchCursor);
|
||||
return searchCursor;
|
||||
}
|
||||
|
||||
void SearchDialog::searchForward() {
|
||||
syncSearchSettings(true);
|
||||
m_replaceCursor = searchNext(false);
|
||||
}
|
||||
|
||||
void SearchDialog::searchBackward() {
|
||||
syncSearchSettings(true);
|
||||
m_replaceCursor = searchNext(true);
|
||||
}
|
||||
|
||||
void SearchDialog::replaceCurrent() {
|
||||
syncSearchSettings(true);
|
||||
Q_ASSERT(m_editor);
|
||||
|
||||
const QString searchText = m_searchText->currentText();
|
||||
if (searchText.isEmpty())
|
||||
return;
|
||||
|
||||
if (m_replaceCursor.isNull() || m_replaceCursor != m_editor->textCursor()) {
|
||||
m_replaceCursor = searchNext(false);
|
||||
return;
|
||||
}
|
||||
|
||||
QString replaceText = m_replaceText->currentText();
|
||||
if (m_escapes->isChecked())
|
||||
replaceText = translateEscapes(replaceText);
|
||||
|
||||
m_replaceCursor.beginEditBlock();
|
||||
m_replaceCursor.removeSelectedText();
|
||||
if (m_regex->isChecked())
|
||||
m_replaceCursor.insertText(regexReplace(replaceText, m_regexMatch));
|
||||
else
|
||||
m_replaceCursor.insertText(replaceText);
|
||||
m_replaceCursor.endEditBlock();
|
||||
|
||||
m_replaceCursor = searchNext(false);
|
||||
}
|
||||
|
||||
void SearchDialog::performReplaceAll(ReplaceAllMode mode) {
|
||||
syncSearchSettings(true);
|
||||
Q_ASSERT(m_editor);
|
||||
|
||||
const QString searchText = m_searchText->currentText();
|
||||
if (searchText.isEmpty())
|
||||
return;
|
||||
|
||||
auto searchCursor = m_editor->textCursor();
|
||||
if (mode == InSelection)
|
||||
searchCursor.setPosition(m_editor->textCursor().selectionStart());
|
||||
else
|
||||
searchCursor.movePosition(QTextCursor::Start);
|
||||
searchCursor = m_editor->textSearch(searchCursor, m_searchParams, true,
|
||||
false, &m_regexMatch);
|
||||
if (searchCursor.isNull()) {
|
||||
QMessageBox::information(this, QString(),
|
||||
tr("The specified text was not found"));
|
||||
return;
|
||||
} else if (mode == InSelection &&
|
||||
searchCursor.selectionEnd() >
|
||||
m_editor->textCursor().selectionEnd()) {
|
||||
WingMessageBox::information(
|
||||
this, QString(),
|
||||
tr("The specified text was not found in the selection"));
|
||||
return;
|
||||
}
|
||||
|
||||
QString replaceText = m_replaceText->currentText();
|
||||
if (m_escapes->isChecked())
|
||||
replaceText = translateEscapes(replaceText);
|
||||
|
||||
searchCursor.beginEditBlock();
|
||||
auto replaceCursor = searchCursor;
|
||||
int replacements = 0;
|
||||
while (!replaceCursor.isNull()) {
|
||||
if (mode == InSelection && replaceCursor.selectionEnd() >
|
||||
m_editor->textCursor().selectionEnd())
|
||||
break;
|
||||
|
||||
replaceCursor.removeSelectedText();
|
||||
if (m_regex->isChecked())
|
||||
replaceCursor.insertText(regexReplace(replaceText, m_regexMatch));
|
||||
else
|
||||
replaceCursor.insertText(replaceText);
|
||||
replaceCursor = m_editor->textSearch(replaceCursor, m_searchParams,
|
||||
false, false, &m_regexMatch);
|
||||
++replacements;
|
||||
}
|
||||
searchCursor.endEditBlock();
|
||||
|
||||
WingMessageBox::information(
|
||||
this, QString(),
|
||||
tr("Successfully replaced %1 matches").arg(replacements));
|
||||
}
|
|
@ -22,8 +22,8 @@
|
|||
#include <QRegularExpressionMatch>
|
||||
#include <QTextCursor>
|
||||
|
||||
#include "dialog/framelessdialogbase.h"
|
||||
#include "wingcodeedit.h"
|
||||
#include "codeeditcontrolwidget.h"
|
||||
#include "control/codeedit.h"
|
||||
|
||||
class QLineEdit;
|
||||
class QComboBox;
|
||||
|
@ -31,82 +31,51 @@ class QCheckBox;
|
|||
class QPushButton;
|
||||
class QTextCursor;
|
||||
|
||||
class SearchWidget : public QWidget {
|
||||
class SearchReplaceWidget : public CodeEditControlWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SearchWidget(WingCodeEdit *editor, QWidget *parent);
|
||||
|
||||
QSize sizeHint() const override {
|
||||
// Make the default just a bit wider
|
||||
const QSize parentHint = QWidget::sizeHint();
|
||||
return {(parentHint.width() * 5) / 4, parentHint.height()};
|
||||
}
|
||||
explicit SearchReplaceWidget(CodeEdit *editor);
|
||||
|
||||
public:
|
||||
void setSearchText(const QString &text);
|
||||
void setReplaceMode(bool b);
|
||||
void activate();
|
||||
|
||||
public Q_SLOTS:
|
||||
void searchNext(bool reverse);
|
||||
virtual void cancel() override;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
private:
|
||||
void updateSettings();
|
||||
|
||||
QTextCursor searchNext(bool reverse);
|
||||
|
||||
QString regexReplace(const QString &text,
|
||||
const QRegularExpressionMatch ®exMatch);
|
||||
|
||||
enum ReplaceAllMode { WholeDocument, InSelection };
|
||||
void replaceCurrent();
|
||||
void performReplaceAll(ReplaceAllMode mode);
|
||||
|
||||
private slots:
|
||||
void searchForward();
|
||||
void searchBackward();
|
||||
|
||||
private:
|
||||
QLineEdit *m_searchText;
|
||||
QLineEdit *m_replaceText;
|
||||
|
||||
QAction *m_caseSensitive;
|
||||
QAction *m_wholeWord;
|
||||
QAction *m_regex;
|
||||
QAction *m_escapes;
|
||||
QAction *m_wrapSearch;
|
||||
QAction *m_replaceSel;
|
||||
|
||||
WingCodeEdit *m_editor;
|
||||
WingCodeEdit::SearchParams m_searchParams;
|
||||
};
|
||||
CodeEdit *m_editor;
|
||||
CodeEdit::SearchParams m_searchParams;
|
||||
|
||||
class SearchDialog : public FramelessDialogBase {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static SearchDialog *create(WingCodeEdit *editor, QWidget *parent);
|
||||
|
||||
virtual ~SearchDialog();
|
||||
|
||||
static QString translateEscapes(const QString &text);
|
||||
static QString regexReplace(const QString &text,
|
||||
const QRegularExpressionMatch ®exMatch);
|
||||
|
||||
public Q_SLOTS:
|
||||
QTextCursor searchNext(bool reverse);
|
||||
|
||||
private Q_SLOTS:
|
||||
void searchForward();
|
||||
void searchBackward();
|
||||
void replaceCurrent();
|
||||
|
||||
private:
|
||||
explicit SearchDialog(QWidget *parent);
|
||||
|
||||
void syncSearchSettings(bool saveRecent);
|
||||
|
||||
enum ReplaceAllMode { WholeDocument, InSelection };
|
||||
void performReplaceAll(ReplaceAllMode mode);
|
||||
|
||||
QComboBox *m_searchText;
|
||||
QComboBox *m_replaceText;
|
||||
QCheckBox *m_caseSensitive;
|
||||
QCheckBox *m_wholeWord;
|
||||
QCheckBox *m_regex;
|
||||
QCheckBox *m_escapes;
|
||||
QCheckBox *m_wrapSearch;
|
||||
QPushButton *m_replaceSelectionButton;
|
||||
QWidget *m_replaceWidgets;
|
||||
QTextCursor m_replaceCursor;
|
||||
|
||||
WingCodeEdit *m_editor;
|
||||
WingCodeEdit::SearchParams m_searchParams;
|
||||
QRegularExpressionMatch m_regexMatch;
|
||||
};
|
||||
|
|
@ -1250,21 +1250,21 @@ void ScriptingDialog::on_delete() {
|
|||
void ScriptingDialog::on_findfile() {
|
||||
auto e = currentEditor();
|
||||
if (e) {
|
||||
// e->editor()->find();
|
||||
e->find();
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptingDialog::on_replace() {
|
||||
auto e = currentEditor();
|
||||
if (e) {
|
||||
// e->editor()->replace();
|
||||
e->replace();
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptingDialog::on_gotoline() {
|
||||
auto e = currentEditor();
|
||||
if (e) {
|
||||
// e->editor()->gotoLine();
|
||||
e->gotoLine();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ protected:
|
|||
}
|
||||
};
|
||||
|
||||
ShowTextDialog::ShowTextDialog(QWidget *parent) : FramelessDialogBase(parent) {
|
||||
ShowTextDialog::ShowTextDialog(QWidget *parent) : FramelessMainWindow(parent) {
|
||||
this->setUpdatesEnabled(false);
|
||||
|
||||
// build up UI
|
||||
|
@ -175,12 +175,12 @@ void ShowTextDialog::on_copyfile() {
|
|||
tr("CopyToClipBoard"));
|
||||
}
|
||||
|
||||
void ShowTextDialog::on_findfile() { m_edit->showSearchBar(true); }
|
||||
|
||||
void ShowTextDialog::on_gotoline() {
|
||||
// m_edit->editor()->gotoLine();
|
||||
void ShowTextDialog::on_findfile() {
|
||||
m_edit->showSearchReplaceBar(true, false);
|
||||
}
|
||||
|
||||
void ShowTextDialog::on_gotoline() { m_edit->showGotoBar(true); }
|
||||
|
||||
void ShowTextDialog::on_encoding() {
|
||||
EncodingDialog d;
|
||||
if (d.exec()) {
|
||||
|
|
|
@ -26,14 +26,14 @@
|
|||
#include "QWingRibbon/ribbontabcontent.h"
|
||||
|
||||
#include "control/codeedit.h"
|
||||
#include "framelessdialogbase.h"
|
||||
#include "dialog/framelessmainwindow.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#include <QShortcut>
|
||||
#include <QStatusBar>
|
||||
#include <QToolButton>
|
||||
|
||||
class ShowTextDialog : public FramelessDialogBase {
|
||||
class ShowTextDialog : public FramelessMainWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ShowTextDialog(QWidget *parent = nullptr);
|
||||
|
|
Loading…
Reference in New Issue