From e10e173cc958ebdd8a0bcee4149d84154e8d9f4b Mon Sep 17 00:00:00 2001 From: "royqh1979@gmail.com" Date: Thu, 21 Oct 2021 17:31:25 +0800 Subject: [PATCH] - enhancement: bookmark view --- NEWS.md | 1 + RedPandaIDE/RedPandaIDE_zh_CN.qm | Bin 95997 -> 97036 bytes RedPandaIDE/RedPandaIDE_zh_CN.ts | 803 ++++++++++++++------------ RedPandaIDE/debugger.cpp | 8 +- RedPandaIDE/editor.cpp | 32 + RedPandaIDE/editor.h | 5 + RedPandaIDE/icons.qrc | 1 + RedPandaIDE/iconsmanager.cpp | 7 + RedPandaIDE/iconsmanager.h | 3 + RedPandaIDE/mainwindow.cpp | 148 ++++- RedPandaIDE/mainwindow.h | 17 + RedPandaIDE/mainwindow.ui | 56 +- RedPandaIDE/systemconsts.h | 1 + RedPandaIDE/widgets/bookmarkmodel.cpp | 234 +++++++- RedPandaIDE/widgets/bookmarkmodel.h | 45 +- 15 files changed, 988 insertions(+), 373 deletions(-) diff --git a/NEWS.md b/NEWS.md index 09f3a0c5..7ed65eda 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,6 +7,7 @@ Version 0.7.0 - enhancement: set mouse wheel scroll speed in the editor general option tab ( 3 lines by default) - fix: don't highlight '#' with spaces preceeding it as error - fix: correctly handle integer with 'L' suffix in #if directives ( so can be correctly parsed ) + - enhancement: bookmark view Version 0.6.8 - enhancement: add link to cppreference in the help menu diff --git a/RedPandaIDE/RedPandaIDE_zh_CN.qm b/RedPandaIDE/RedPandaIDE_zh_CN.qm index 6eab60c8cbc3c80932729815fba7e06d70d753d7..0119b85ba8fdda413c2298d09ff7eb17c951608d 100644 GIT binary patch delta 9803 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

s1f>N$OiM;l% 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ⅆZF?BO(;<(Pj?}jBdC+l?uL}NSEpH( z!!>u+hZ;jkqu+tBOpLYq@J5`!wo{)lyt|1dR8#edcktEGVc;EbrTTOX($4xA2vfz6 zmH0ScopWUd(Sj;%&6;c^`(XQ`zSZ{)#|)IaXS!oK&_hF|M217*JYPtDd#t5-%c`wr^AX-K!;{WK~! zSjMVSql+&?dVZ2PF-}uArj%%ATaD?&XjIAZ8q+s$;cA)2>^hJ0hZ@^OONoYuYTB>F z1opUSI_7OB+IC6PRfmSh+EL^BX&5BC(4gr%3MOl?N#kZ=ji{e2@$E{9KXyv|!)ttl zICMOpH33R|xNW?|S8196*WKuLJ8LF9dxre4rmy%W{vI!R;gVz@m=BD zii?`~N{oDYm1g6zM@XODnvJQ@_R8m)Eq9T}cGa3~%3QeYp(e=;t{nYElVn{JBkMK0 z9$;nl??g>%Yq;9XPLo=b-f<5#sT;je|F<>O9Gqi?{XcKb!O~|$rdKrS!xORkEz+Fm zjqbR_Ta(j&8_Mz@&Dlxou{3+9DTvsQYW7r9c<3osN^dk5n;>oLtkDz~zeoAKt9hK! z8#A`oRCK$EUe88Tc^wu`jn!1;1!1jtPgC_At{U)NQ}wbD>c7np&6^mE=T(foghalMP!APrF*drWMY`H5&!C$Ys@JqBJaTGi}) z-U|?0%22+4cM@CaVzDFIPNL&yiI-JkYv=7~V*7|~S7u^B*FggghH;{8J_h12$t~ZAddHkg=(9NVLW~v4Hzs=F^h$TOvGu8O^C)d5vLpEWe|+bV#Eeld|;=z za2156tE;#)7BSFag1GF54rMe+Tt|qJr**{jUWnSR=fn+{;lrYLV!Z1t47i!NsV83O zEf+V{oVTtPYkuM(OJ6bZ03>*zmAI|zE^J_CirXvjT(9*KuRIbB$#fT*?(2y@qq8U9C+Cdb9>Fl%(J2gQ?bQ9c{I7EiGmNIxI(RLU^4>pR7~U@xlKPTyGYNFZ}zW zF_DXoq z(VA1WUMffHh{6FXB$s*GFwtd~+0!Kib#Naeo2RetZl; zvKpoRl!F(ij?n&?4~taUYk#^Ro6djJ{)#O|a29B*6XCLtopthbJoo#WPPN?$F_)*) zgg?iPBi88j6U(s+rq|V5ejgnW)0qWlqSacYGmG+qiN@&6YxeWXJLoLbQ}82oFP&x5 zcKH03&bm$(gh#7$o>2-*wa~c?#D;|Wq0ZeU2Rcz(=e1)l23D*a@&ex(+D#YG1M7+X zoNnyxx7gk*)ddzAUf|cNJYCS4OGvl9y2+Qyk@tgiQ+gm@Q=)ZK2B354HeEO4F7#mV zR^1YB?0kOes9Pokqekd-D>uW(o|kp&$}rHgCAzIc)1mE4bvr)E5F>MRsoNr<7pA(s z&rr_oJap+ZZb3<#>JI0?lK({Ojv8*;qP@PLJ6?zpS=`i}&BlxhvUL}>*`h&Mp}X17 z1u!M@xm6c6`b~n^L*Q&9){a5!@u@q(2R`=~leTE!`@Fnee}6x)PQdW{aP6wOyKnEI^{sq6ZPwx zAuZazl=!XENakpvPpE>x^slGiqMC($fRXwwtzoGrZS>oAfYpLNIc^swVyoZ10%dwn zls={VbE0qV`n~56OUvT**^3|HH=>^UQ|&PDn{AC`?F}vTXWJmXE-%!dtH6T7JxyN{ z6Nd+5^rbyau)#P*|E~|C{EkxpV9XSl)Lvid1k-ts&{sV|@yTAJ|MDRP`v6t?ABP)2 zkW~6#qv~T#IZgjJ5HT`(1G*2NUT_L;PEG#%HZbKiLjaovB|XYTzGyy*WIB=jEu diff --git a/RedPandaIDE/RedPandaIDE_zh_CN.ts b/RedPandaIDE/RedPandaIDE_zh_CN.ts index 342ccfc1..11ab5320 100644 --- a/RedPandaIDE/RedPandaIDE_zh_CN.ts +++ b/RedPandaIDE/RedPandaIDE_zh_CN.ts @@ -95,35 +95,73 @@ BacktraceModel - + Function 函数 - + Filename 文件名 - + Line - BreakpointModel + BookmarkModel - - Filename - 文件名 + + Save file '%1' failed. + 保存文件'%1'失败。 - + + Can't open file '%1' for write. + 无法写入文件'%1'. + + + + Error in json file '%1':%2 : %3 + JSON文件'%1':%2中存在错误:%3 + + + + Can't open file '%1' for read. + 无法读取文件'%1'. + + + + Description + 描述 + + + Line + + + Filename + 文件名 + + + + BreakpointModel + Filename + 文件名 + + + + Line + + + + Condition 条件 @@ -954,10 +992,10 @@ Are you really want to continue? - - - - + + + + Error 错误 @@ -972,55 +1010,55 @@ Are you really want to continue? 另存为 - + The text to be copied exceeds count limit! 要复制的内容超过了行数限制! - + The text to be copied exceeds character limit! 要复制的内容超过了字符数限制! - + The text to be cut exceeds count limit! 要剪切的内容超过了行数限制! - + The text to be cut exceeds character limit! 要剪切的内容超过了字符数限制! - + Print Document 打印文档 - - - + + + Ctrl+click for more info Ctrl+单击以获取更多信息 - - + + Symbol '%1' not found! 未找到符号'%1'! - + Break point condition 断点条件 - + Enter the condition of the breakpoint: 输入当前断点的生效条件: - + Readonly 只读 @@ -2728,50 +2766,50 @@ Are you really want to continue? 小熊猫C++ - - + + Issues 编译器 - + Compile Log 编译日志 - + File 文件 - + Tools 工具 - - + + Run 运行 - + Edit 编辑 - - + + Project 项目 - + Watch 监视 - + Structure 结构 @@ -2784,82 +2822,82 @@ Are you really want to continue? 资源 - - - - + + + + Debug 调试 - + Evaluate: 求值 - + Debug Console 调试主控台 - + Call Stack 调用栈 - + Breakpoints 断点 - + Locals 本地变量 - - + + Search 查找 - + History: 历史: - + Search Again 重新查找 - + Replace with: 替换为: - + Replace 替换 - + Close 关闭 - + Execute 运行 - - + + Code 代码 - + Window 窗口 @@ -2877,660 +2915,681 @@ Are you really want to continue? 新建 - + Ctrl+N Ctrl+N - + Open... 打开... - + Ctrl+O Ctrl+O - + Save 保存 - + Ctrl+S Ctrl+S - + Save As... 另存为... - + Save As 另存为 - + Save All 全部保存 - + Ctrl+Shift+S Ctrl+Shift+S - + Options 选项 - - - - - - - + + + + + + + Compile 编译 - + F9 F9 - + F10 F10 - + Undo 恢复 - + Ctrl+Z Ctrl+Z - + Redo 重做 - + Ctrl+Y Ctrl+Y - + Cut 剪切 - + Ctrl+X Ctrl+X - - - + + + Copy 复制 - + Ctrl+C Ctrl+C - - + + Paste 粘贴 - + Ctrl+V Ctrl+V - - + + Select All 选择全部 - + Ctrl+A Ctrl+A - + Indent 缩进 - + UnIndent 取消缩进 - + Toggle Comment 切换注释 - + Ctrl+/ Ctrl+/ - + Collapse All 全部收起 - + Uncollapse All 全部展开 - + Encode in ANSI 使用ANSI编码 - + Encode in UTF-8 使用UTF-8编码 - + Auto Detect 自动检测 - + Convert to ANSI 转换为ANSI编码 - + Convert to UTF-8 转换为UTF-8编码 - - + + Compile & Run 编译运行 - + F11 F11 - - + + Rebuild All 全部重编译 - + F12 F12 - + Stop Execution 停止执行 - + F6 F6 - + F5 F5 - + Step Over 单步跳过 - + F7 F7 - + Step Into 单步进入 - + Memory 内存 - + Address Expression: Address: 地址表达式: - + Cancel 取消 - + TODO TODO - + + Bookmark + 书签 + + + Help 帮助 - + Refactor 重构 - + Main 主工具栏 - + Compiler Set 编译器配置集 - - + + New Source File 新建源代码文件 - + Tab Tab - + Shift+Tab Shift+Tab - + F8 F8 - + Step Out 单步跳出 - + Ctrl+F8 Ctrl+F8 - + Run To Cursor 执行到光标处 - + Ctrl+F5 Ctrl+F5 - + Continue 继续执行 - + F4 F4 - + Add Watch... 添加监视 - + View CPU Window... 打开CPU信息窗口... - + Exit 退出 - + Find... 查找... - + Ctrl+F Ctrl+F - + Find in Files... 在文件中查找... - + Ctrl+Shift+F Ctrl+Shift+F - + Replace... 替换 - + Ctrl+R Ctrl+R - + Find Next 查找下一个 - + F3 F3 - + Find Previous 查找前一个 - + Shift+F3 Shift+F3 - + Remove Watch 删除监视 - + + Remove All 清除全部监视 - + Modify Watch... 修改监视值 - + Reformat Code 对代码重新排版 - + Ctrl+Shift+A Ctrl+Shift+A - + Go back 前一次编辑位置 - + Ctrl+Alt+Left Ctrl+Alt+Left - + Forward 后一次编辑位置 - + Ctrl+Alt+Right Ctrl+Alt+Right - + Ctrl+W Ctrl+W - + Close All 全部关闭 - + Ctrl+Shift+W Ctrl+Shift+W - + Maximize Editor 最大化编辑器 - + Ctrl+F11 Ctrl+F11 - + Next 下一窗口 - + Ctrl+Tab Ctrl+Tab - + Previous 前一窗口 - + Ctrl+Shift+Tab Ctrl+Shift+Tab - + Toggle breakpoint 切换断点 - + Ctrl+F4 Ctrl+F4 - - + + Clear all breakpoints 删除所有断点 - + Breakpoint property... 设置断点条件... - + Goto Declaration 跳转到声明处 - + Goto Definition 跳转到定义处 - + Find references 查找符号的引用 - + Open containing folder 打开所在的文件夹 - + Ctrl+B Ctrl+B - + Open a terminal here 打开命令行窗口 - + File Properties... 文件属性... - + Close Project 关闭项目 - + Project options 项目属性 - + New Project... 新建项目... - + New File 新建项目文件 - + Add to project... 添加到项目... - + Remove from project 从项目删除 - + View Makefile 查看Makefile - + Clean 清理构建文件 - + Open Folder in Explorer 在浏览器中打开 - + Open In Terminal 在终端中打开 - + About 关于 - - + + Rename Symbol 重命名符号 - + Shift+F6 Shift+F6 - + Print... 打印... - + Ctrl+P Ctrl+P - - + + Export As RTF 导出为RTF - - + + Export As HTML 导出为HTML - + Move To Other View 移动到其他视图 - + Ctrl+M Ctrl+M - + C/C++ Reference C/C++参考 - + EGE Manual EGE图形库手册 - + + Add Bookmark + 添加书签 + + + + Remove Bookmark + 删除书签 + + + + Modify Bookmark Description + 修改书签说明 + + + File Encoding 文件编码 @@ -3540,32 +3599,32 @@ Are you really want to continue? 文件历史 - - - - - - + + + + + + Debugging 正在调试 - - - - - - + + + + + + Running 正在运行 - - - - - - + + + + + + Compiling 正在编译 @@ -3574,168 +3633,168 @@ Are you really want to continue? 行:%1 列:%2 已选择:%3 总行数:%4 总长度:%5 - + Line:%1 Col:%2 Selected:%3 Lines:%4 Length:%5 Line: %1 Col: %2 Selected: %3 Lines: %4 Length: %5 行: %1 列: %2 已选择 :%3 总行数: %4 总长度: %5 - + Read Only 只读 - + Insert 插入 - + Overwrite 覆写 - + Close project 关闭项目 - + Are you sure you want to close %1? 你确定要关闭'%1'吗? - - + + Confirm 确认 - - - + + + Source file is not compiled. 源文件尚未编译。 - - + + Compile now? 现在编译? - - - + + + Source file is more recent than executable. 源文件比可执行程序新。 - + Recompile now? 重新编译? - + No compiler set 无编译器设置 - + No compiler set is configured. 没有配置编译器设置。 - + Can't start debugging. 无法启动调试器 - - + + Enable debugging 启用调试参数 - - + + You have not enabled debugging info (-g3) and/or stripped it from the executable (-s) in Compiler Options.<BR /><BR />Do you want to correct this now? 当前编译设置中未启用调试选项(-g3),或启用了信息剥除选项(-s)<br /><br/>是否纠正这一问题? - + Project not built 项目尚未构建 - + Project hasn't been built. Build it now? 项目尚未构建。是否构建? - + Host applcation missing 宿主程序不存在 - + DLL project needs a host application to run. 动态链接库(DLL)需要一个宿主程序来运行。 - + But it's missing. 但它不存在。 - + Host application not exists 宿主程序不存在 - + Host application file '%1' doesn't exist. 宿主程序'%1'不存在。 - + Recompile? 重新编译? - - + + Save last open info error 保存上次打开信息失败 - + Can't remove old last open information file '%1' 无法删除旧上次打开信息文件'%1' - + Can't save last open info file '%1' 无法保存上次打开信息文件'%1' - + Load last open info error 载入上次打开信息失败 - + Can't load last open info file '%1' 无法载入上次打开信息文件'%1' - + Copy all 全部复制 - - + + Clear 清除 @@ -3750,232 +3809,256 @@ Are you really want to continue? 插入代码段 - + + Remove + 删除 + + + + Modify Description + 修改描述 + + + + + + Bookmark Description + 书签描述 + + + + + + Description: + 描述: + + + Show debug logs in the debug console 在调试主控台中显示调试器输出 - + Remove this search 清除这次搜索 - + Clear all searches 删除所有搜索 - + Breakpoint condition... 断点条件... - + Break point condition 断点条件 - + Enter the condition of the breakpoint: 输入当前断点的生效条件: - + Remove all breakpoints 清除所有断点 - + Rename File 重命名文件 - - + + Add Folder 添加文件夹 - + New folder 新文件夹 - + Folder name: 文件夹: - + Rename Folder 重命名 - + Remove Folder 删除文件夹 - + Sort By Type 按类型排序 - + Sort alphabetically 按名称排序 - + Show inherited members 显示继承的成员 - + Goto declaration 跳转到声明处 - + Goto definition 跳转到定义处 - + Character sets 字符集 - + %1 files autosaved 已自动保存%1个文件 - + Save project 保存项目 - + The project '%1' has modifications. 项目'%1'有改动。 - + Do you want to save it? 需要保存吗? - + Do you really want to clear all breakpoints in this file? 您真的要清除该文件的所有断点吗? - + New project 新建项目 - + Close %1 and start new project? 关闭'%1'以打开新项目? - + Folder not exist 文件夹不存在 - + Folder '%1' doesn't exist. Create it now? 文件夹'%1'不存在。是否创建? - + Can't create folder 无法创建文件夹 - + Failed to create folder '%1'. 创建文件夹'%1'失败。 - + Save new project as - + Red panda Dev-C++ project file (*.dev) 小熊猫Dev-C++项目文件 (*.dev) - + New project fail 新建项目失败 - + Can't assign project template 无法使用模板创建项目 - + Add to project 添加到项目 - + Rename Error 重命名出错 - + Symbol '%1' is defined in system header. 符号'%1'在系统头文件中定义,无法修改。 - + New Name 新名称 - - + + Replace Error 替换出错 - + Can't open file '%1' for replace! 无法打开文件'%1'进行替换! - + Contents has changed since last search! 内容和上次查找时不一致。 - + Rich Text Format Files (*.rtf) RTF格式文件 (*.rtf) - + HTML Files (*.html) HTML文件 (*.html) - - - - - - - - - + + + + + + + + + Error 错误 @@ -3985,75 +4068,75 @@ Are you really want to continue? 项目历史 - + File '%1' was changed. 磁盘文件'%1'已被修改。 - + Reload its content from disk? 是否重新读取它的内容? - + File '%1' was removed. 磁盘文件'%1'已被删除。 - + Keep it open? 是否保持它在小熊猫C++中打开的编辑窗口? - + Open 打开 - + Compile Failed 编译失败 - + Run Failed 运行失败 - - + + Confirm Convertion 确认转换 - - + + The editing file will be saved using %1 encoding. <br />This operation can't be reverted. <br />Are you sure to continue? 当前编辑器中的文件将会使用%1编码保存。<br />这项操作无法被撤回。<br />你确定要继续吗? - + New Watch Expression 新监视表达式 - + Enter Watch Expression (it is recommended to use 'this->' for class members): 输入监视表达式 - + Parsing file %1 of %2: "%3" (%1/%2)正在解析文件"%3" - - + + Done parsing %1 files in %2 seconds 完成%1个文件的解析,用时%2秒 - + (%1 files per second) (每秒%1个文件) @@ -4135,62 +4218,62 @@ Are you really want to continue? 无法保存文件'%1'. - + File Exists 文件已存在 - + File '%1' is already in the project 文件'%1'已在项目中 - + Project Updated 项目已升级 - + Your project was succesfully updated to a newer file format! 已成功将项目升级到新的格式 - + If something has gone wrong, we kept a backup-file: '%1'... 旧项目文件备份在'%1'。 - + Settings need update 设置需要更新 - + The compiler settings format of Dev-C++ has changed. Dev-C++的编译器设置格式已发生改变。 - + Please update your settings at Project >> Project Options >> Compiler and save your project. 请在项目 >> 项目属性 >> 编译器设置中修改您的设置并保存您的项目 - + Compiler not found 未找到编译器 - + The compiler set you have selected for this project, no longer exists. 您为该项目设置的编译器不存在。 - + It will be substituted by the global compiler set. 它将会被全局编译器设置代替。 - + Developed using the Red Panda Dev-C++ IDE 使用小熊猫Dev-C++编辑器开发 @@ -4576,24 +4659,24 @@ Are you really want to continue? ProjectModel - + File exists 文件已存在 - + File '%1' already exists. Delete it now? 文件'%1'已存在。是否删除? - - + + Remove failed 删除失败 - - + + Failed to remove file '%1' 无法删除文件'%1' @@ -4820,12 +4903,12 @@ Are you really want to continue? QObject - + Save 保存 - + Save changes to %1? 将修改保存到"%1"? @@ -5459,17 +5542,17 @@ Are you really want to continue? RegisterModel - + Register 寄存器 - + Value(Hex) 值(HEX) - + Value(Dec) 值(DEC) @@ -6127,8 +6210,8 @@ Are you really want to continue? SynEdit - - + + The highlighter seems to be in an infinite loop 高亮处理进入了死循环 @@ -6297,12 +6380,12 @@ Are you really want to continue? WatchModel - + Expression 表达式 - + Value @@ -6417,7 +6500,7 @@ Are you really want to continue? Mouse Wheel Scroll Speed - 鼠标滚轮卷轴速度(行) + 鼠标滚轮卷轴速度(行) diff --git a/RedPandaIDE/debugger.cpp b/RedPandaIDE/debugger.cpp index 6343e09b..ee803d5a 100644 --- a/RedPandaIDE/debugger.cpp +++ b/RedPandaIDE/debugger.cpp @@ -1812,32 +1812,30 @@ PBreakpoint BreakpointModel::breakpoint(int index) const void BreakpointModel::onFileDeleteLines(const QString &filename, int startLine, int count) { - beginResetModel(); for (int i = mList.count()-1;i>=0;i--){ PBreakpoint breakpoint = mList[i]; if (breakpoint->filename == filename && breakpoint->line>=startLine) { if (breakpoint->line >= startLine+count) { breakpoint->line -= count; + emit dataChanged(createIndex(i,0),createIndex(i,2)); } else { - mList.removeAt(i); + removeBreakpoint(i); } } } - endResetModel(); } void BreakpointModel::onFileInsertLines(const QString &filename, int startLine, int count) { - beginResetModel(); for (int i = mList.count()-1;i>=0;i--){ PBreakpoint breakpoint = mList[i]; if (breakpoint->filename == filename && breakpoint->line>=startLine) { breakpoint->line+=count; + emit dataChanged(createIndex(i,0),createIndex(i,2)); } } - endResetModel(); } diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index 497b6006..3cb29d6e 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -779,6 +779,9 @@ void Editor::onGutterPaint(QPainter &painter, int aLine, int X, int Y) } return; } + if (hasBookmark(aLine)) { + painter.drawPixmap(X,Y,*(pIconsManager->bookmark())); + } } } @@ -1500,7 +1503,9 @@ void Editor::onLinesDeleted(int first, int count) { pMainWindow->caretList().linesDeleted(this,first,count); pMainWindow->debugger()->breakpointModel()->onFileDeleteLines(mFilename,first,count); + pMainWindow->bookmarkModel()->onFileDeleteLines(mFilename,first,count); resetBreakpoints(); + resetBookmarks(); if (!pSettings->editor().syntaxCheckWhenLineChanged()) { //todo: update syntax issues } @@ -1510,7 +1515,9 @@ void Editor::onLinesInserted(int first, int count) { pMainWindow->caretList().linesInserted(this,first,count); pMainWindow->debugger()->breakpointModel()->onFileInsertLines(mFilename,first,count); + pMainWindow->bookmarkModel()->onFileInsertLines(mFilename,first,count); resetBreakpoints(); + resetBookmarks(); if (!pSettings->editor().syntaxCheckWhenLineChanged()) { //todo: update syntax issues } @@ -1531,6 +1538,12 @@ bool Editor::isBraceChar(QChar ch) } } +void Editor::resetBookmarks() +{ + mBookmarkLines=pMainWindow->bookmarkModel()->bookmarksInFile(mFilename); + invalidate(); +} + void Editor::resetBreakpoints() { mBreakpointLines.clear(); @@ -3523,6 +3536,25 @@ bool Editor::hasBreakpoint(int line) return mBreakpointLines.contains(line); } +void Editor::addBookmark(int line, const QString& description) +{ + mBookmarkLines.insert(line); + pMainWindow->bookmarkModel()->addBookmark(mFilename,line,description); + invalidateGutterLine(line); +} + +void Editor::removeBookmark(int line) +{ + mBookmarkLines.remove(line); + pMainWindow->bookmarkModel()->removeBookmark(mFilename,line); + invalidateGutterLine(line); +} + +bool Editor::hasBookmark(int line) +{ + return mBookmarkLines.contains(line); +} + void Editor::removeBreakpointFocus() { if (mActiveBreakpointLine!=-1) { diff --git a/RedPandaIDE/editor.h b/RedPandaIDE/editor.h index c433135e..160fcafd 100644 --- a/RedPandaIDE/editor.h +++ b/RedPandaIDE/editor.h @@ -147,6 +147,9 @@ public: void toggleBreakpoint(int line); void clearBreakpoints(); bool hasBreakpoint(int line); + void addBookmark(int line,const QString& description); + void removeBookmark(int line); + bool hasBookmark(int line); void removeBreakpointFocus(); void modifyBreakpointProperty(int line); void setActiveBreakpointFocus(int Line, bool setFocus=true); @@ -177,6 +180,7 @@ private slots: private: bool isBraceChar(QChar ch); + void resetBookmarks(); void resetBreakpoints(); QChar getCurrentChar(); bool handleSymbolCompletion(QChar key); @@ -242,6 +246,7 @@ private: int mLineCount; int mGutterClickedLine; QSet mBreakpointLines; + QSet mBookmarkLines; int mActiveBreakpointLine; PCppParser mParser; std::shared_ptr mCompletionPopup; diff --git a/RedPandaIDE/icons.qrc b/RedPandaIDE/icons.qrc index 7cfe07e6..e33ad503 100644 --- a/RedPandaIDE/icons.qrc +++ b/RedPandaIDE/icons.qrc @@ -486,5 +486,6 @@ images/classparser/var_private.ico images/classparser/var_protected.ico images/classparser/var_public.ico + images/editor/bookmark.png diff --git a/RedPandaIDE/iconsmanager.cpp b/RedPandaIDE/iconsmanager.cpp index 3b644512..52f4f8bb 100644 --- a/RedPandaIDE/iconsmanager.cpp +++ b/RedPandaIDE/iconsmanager.cpp @@ -8,6 +8,8 @@ IconsManager::IconsManager(QObject *parent) : QObject(parent) mSyntaxWarning = std::make_shared(":/icons/images/editor/syntaxwarning.png"); mBreakpoint = std::make_shared(":/icons/images/editor/breakpoint.png"); mActiveBreakpoint = std::make_shared(":/icons/images/editor/currentline.png"); + mBookmark = std::make_shared(":/icons/images/editor/bookmark.png"); + } PIcon IconsManager::syntaxError() const @@ -29,3 +31,8 @@ PIcon IconsManager::activeBreakpoint() const { return mActiveBreakpoint; } + +const PIcon &IconsManager::bookmark() const +{ + return mBookmark; +} diff --git a/RedPandaIDE/iconsmanager.h b/RedPandaIDE/iconsmanager.h index ed4623fb..5a84f44c 100644 --- a/RedPandaIDE/iconsmanager.h +++ b/RedPandaIDE/iconsmanager.h @@ -20,12 +20,15 @@ public: PIcon activeBreakpoint() const; + const PIcon &bookmark() const; + signals: private: PIcon mSyntaxError; PIcon mSyntaxWarning; PIcon mBreakpoint; PIcon mActiveBreakpoint; + PIcon mBookmark; }; extern IconsManager* pIconsManager; diff --git a/RedPandaIDE/mainwindow.cpp b/RedPandaIDE/mainwindow.cpp index 90653968..9525a2be 100644 --- a/RedPandaIDE/mainwindow.cpp +++ b/RedPandaIDE/mainwindow.cpp @@ -149,6 +149,10 @@ MainWindow::MainWindow(QWidget *parent) mCodeSnippetManager->load(); mToolsManager = std::make_shared(); mToolsManager->load(); + mBookmarkModel = std::make_shared(); + mBookmarkModel->load(includeTrailingPathDelimiter(pSettings->dirs().config()) + +DEV_BOOKMARK_FILE); + ui->tableBookmark->setModel(mBookmarkModel.get()); mSearchResultTreeModel = std::make_shared(&mSearchResultModel); mSearchResultListModel = std::make_shared(&mSearchResultModel); mSearchViewDelegate = std::make_shared(mSearchResultTreeModel); @@ -267,6 +271,10 @@ void MainWindow::updateEditorActions() ui->actionClose->setEnabled(false); ui->actionClose_All->setEnabled(false); + + ui->actionAdd_bookmark->setEnabled(false); + ui->actionRemove_Bookmark->setEnabled(false); + ui->actionModify_Bookmark_Description->setEnabled(false); } else { ui->actionAuto_Detect->setEnabled(true); ui->actionEncode_in_ANSI->setEnabled(true); @@ -302,7 +310,12 @@ void MainWindow::updateEditorActions() ui->actionClose->setEnabled(true); ui->actionClose_All->setEnabled(true); - } + + int line = e->caretY(); + ui->actionAdd_bookmark->setEnabled(e->lines()->count()>0 && !e->hasBookmark(line)); + ui->actionRemove_Bookmark->setEnabled(e->hasBookmark(line)); + ui->actionModify_Bookmark_Description->setEnabled(e->hasBookmark(line)); + } updateCompileActions(); @@ -1478,6 +1491,15 @@ void MainWindow::includeOrSkipDirs(const QStringList &dirs, bool skip) } } +void MainWindow::onBookmarkContextMenu(const QPoint &pos) +{ + QMenu menu(this); + menu.addAction(mBookmark_Remove); + menu.addAction(mBookmark_RemoveAll); + menu.addAction(mBookmark_Modify); + menu.exec(ui->tableBookmark->mapToGlobal(pos)); +} + void MainWindow::saveLastOpens() { QString filename = includeTrailingPathDelimiter(pSettings->dirs().config()) + DEV_LASTOPENS_FILE; @@ -1622,6 +1644,45 @@ void MainWindow::buildContextMenus() connect(ui->watchView,&QWidget::customContextMenuRequested, this, &MainWindow::onWatchViewContextMenu); + //context menu signal for the bookmark view + ui->tableBookmark->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->tableBookmark,&QWidget::customContextMenuRequested, + this, &MainWindow::onBookmarkContextMenu); + mBookmark_Remove=createActionFor( + tr("Remove"), + ui->tableBookmark); + connect(mBookmark_Remove, &QAction::triggered, + [this]() { + QModelIndex index = ui->tableBookmark->currentIndex(); + if (index.isValid()) { + mBookmarkModel->removeBookmarkAt(index.row()); + } + }); + mBookmark_RemoveAll=createActionFor( + tr("Remove All"), + ui->tableBookmark); + connect(mBookmark_RemoveAll, &QAction::triggered, + [this]() { + mBookmarkModel->clear(); + }); + mBookmark_Modify=createActionFor( + tr("Modify Description"), + ui->tableBookmark); + connect(mBookmark_Modify, &QAction::triggered, + [this]() { + QModelIndex index = ui->tableBookmark->currentIndex(); + if (index.isValid()) { + PBookmark bookmark = mBookmarkModel->bookmark(index.row()); + if (bookmark) { + QString desc = QInputDialog::getText(ui->tableBookmark,tr("Bookmark Description"), + tr("Description:"),QLineEdit::Normal, + bookmark->description); + desc = desc.trimmed(); + mBookmarkModel->updateDescription(bookmark->filename,bookmark->line,desc); + } + mBookmarkModel->clear(); + }); + //context menu signal for the watch view ui->debugConsole->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->debugConsole,&QWidget::customContextMenuRequested, @@ -2271,7 +2332,9 @@ void MainWindow::onEditorContextMenu(const QPoint &pos) QMenu menu(this); BufferCoord p; mEditorContextMenuPos = pos; + int line; if (editor->getPositionOfMouse(p)) { + line=p.Line; //mouse on editing area menu.addAction(ui->actionCompile_Run); menu.addAction(ui->actionDebug); @@ -2296,6 +2359,10 @@ void MainWindow::onEditorContextMenu(const QPoint &pos) menu.addAction(ui->actionToggle_Breakpoint); menu.addAction(ui->actionClear_all_breakpoints); menu.addSeparator(); + menu.addAction(ui->actionAdd_bookmark); + menu.addAction(ui->actionRemove_Bookmark); + menu.addAction(ui->actionModify_Bookmark_Description); + menu.addSeparator(); menu.addAction(ui->actionFile_Properties); //these actions needs parser @@ -2304,16 +2371,25 @@ void MainWindow::onEditorContextMenu(const QPoint &pos) ui->actionFind_references->setEnabled(!editor->parser()->parsing()); } else { //mouse on gutter - int line; + if (!editor->getLineOfMouse(line)) line=-1; menu.addAction(ui->actionToggle_Breakpoint); menu.addAction(ui->actionBreakpoint_property); menu.addAction(ui->actionClear_all_breakpoints); - ui->actionBreakpoint_property->setEnabled(editor->hasBreakpoint(line)); + menu.addSeparator(); + menu.addAction(ui->actionAdd_bookmark); + menu.addAction(ui->actionRemove_Bookmark); + menu.addAction(ui->actionModify_Bookmark_Description); } + ui->actionBreakpoint_property->setEnabled(editor->hasBreakpoint(line)); + ui->actionAdd_bookmark->setEnabled( + line>=0 && editor->lines()->count()>0 + && !editor->hasBreakpoint(line) + ); + ui->actionRemove_Bookmark->setEnabled(editor->hasBreakpoint(line)); + ui->actionModify_Bookmark_Description->setEnabled(editor->hasBreakpoint(line)); menu.exec(editor->viewport()->mapToGlobal(pos)); - } void MainWindow::onEditorRightTabContextMenu(const QPoint &pos) @@ -2617,6 +2693,8 @@ void MainWindow::closeEvent(QCloseEvent *event) { settings.setLeftPanelIndex(ui->tabInfos->currentIndex()); settings.setLeftPanelOpenned(mLeftPanelOpenned); settings.save(); + mBookmarkModel->save(includeTrailingPathDelimiter(pSettings->dirs().config()) + +DEV_BOOKMARK_FILE); } if (!mShouldRemoveAllSettings && pSettings->editor().autoLoadLastFiles()) { @@ -4313,3 +4391,65 @@ void MainWindow::on_actionEGE_Manual_triggered() QDesktopServices::openUrl(QUrl("https://xege.org/ege-open-source")); } +const PBookmarkModel &MainWindow::bookmarkModel() const +{ + return mBookmarkModel; +} + + +void MainWindow::on_actionAdd_bookmark_triggered() +{ + Editor* editor = mEditorList->getEditor(); + int line; + if (editor && editor->pointToLine(mEditorContextMenuPos,line)) { + if (editor->lines()->count()<=0) + return; + QString desc = QInputDialog::getText(editor,tr("Bookmark Description"), + tr("Description:"),QLineEdit::Normal, + editor->lines()->getString(line-1).trimmed()); + desc = desc.trimmed(); + editor->addBookmark(line,desc); + } +} + + +void MainWindow::on_actionRemove_Bookmark_triggered() +{ + Editor* editor = mEditorList->getEditor(); + int line; + if (editor && editor->pointToLine(mEditorContextMenuPos,line)) { + editor->removeBookmark(line); + } +} + + +void MainWindow::on_tableBookmark_doubleClicked(const QModelIndex &index) +{ + if (!index.isValid()) + return; + PBookmark bookmark = mBookmarkModel->bookmark(index.row()); + if (bookmark) { + Editor *editor= mEditorList->getEditorByFilename(bookmark->filename); + if (editor) { + editor->setCaretPositionAndActivate(bookmark->line,1); + } + } +} + + +void MainWindow::on_actionModify_Bookmark_Description_triggered() +{ + Editor* editor = mEditorList->getEditor(); + int line; + if (editor && editor->pointToLine(mEditorContextMenuPos,line)) { + PBookmark bookmark = mBookmarkModel->bookmark(editor->filename(),line); + if (bookmark) { + QString desc = QInputDialog::getText(editor,tr("Bookmark Description"), + tr("Description:"),QLineEdit::Normal, + bookmark->description); + desc = desc.trimmed(); + mBookmarkModel->updateDescription(editor->filename(),line,desc); + } + } +} + diff --git a/RedPandaIDE/mainwindow.h b/RedPandaIDE/mainwindow.h index 23bd9ca2..0689075c 100644 --- a/RedPandaIDE/mainwindow.h +++ b/RedPandaIDE/mainwindow.h @@ -16,6 +16,7 @@ #include "todoparser.h" #include "toolsmanager.h" #include "widgets/labelwithmenu.h" +#include "widgets/bookmarkmodel.h" QT_BEGIN_NAMESPACE @@ -137,6 +138,8 @@ public: bool shouldRemoveAllSettings() const; + const PBookmarkModel &bookmarkModel() const; + public slots: void onCompileLog(const QString& msg); void onCompileIssue(PCompileIssue issue); @@ -194,6 +197,7 @@ private slots: void onFileChanged(const QString& path); void onWatchViewContextMenu(const QPoint& pos); + void onBookmarkContextMenu(const QPoint& pos); void onTableIssuesContextMenu(const QPoint& pos); void onSearchViewContextMenu(const QPoint& pos); void onBreakpointsViewContextMenu(const QPoint& pos); @@ -407,6 +411,14 @@ private slots: void on_actionEGE_Manual_triggered(); + void on_actionAdd_bookmark_triggered(); + + void on_actionRemove_Bookmark_triggered(); + + void on_tableBookmark_doubleClicked(const QModelIndex &index); + + void on_actionModify_Bookmark_Description_triggered(); + private: Ui::MainWindow *ui; EditorList *mEditorList; @@ -436,6 +448,7 @@ private: TodoModel mTodoModel; SearchResultModel mSearchResultModel; + PBookmarkModel mBookmarkModel; PSearchResultListModel mSearchResultListModel; PSearchResultTreeModel mSearchResultTreeModel; PSearchResultTreeViewDelegate mSearchViewDelegate; @@ -497,6 +510,10 @@ private: QAction * mDebugConsole_Copy; QAction * mDebugConsole_Paste; QAction * mDebugConsole_SelectAll; + //action for bookmarks + QAction * mBookmark_Remove; + QAction * mBookmark_RemoveAll; + QAction * mBookmark_Modify; // QWidget interface protected: diff --git a/RedPandaIDE/mainwindow.ui b/RedPandaIDE/mainwindow.ui index 4f3d3dfc..d207278e 100644 --- a/RedPandaIDE/mainwindow.ui +++ b/RedPandaIDE/mainwindow.ui @@ -295,7 +295,7 @@ QTabWidget::South - 4 + 5 @@ -859,6 +859,33 @@ + + + + :/icons/images/newlook24/039-gobook.png:/icons/images/newlook24/039-gobook.png + + + Bookmark + + + + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + + + @@ -956,6 +983,10 @@ + + + + @@ -1885,6 +1916,29 @@ EGE Manual + + + + :/icons/images/newlook24/003-addbook.png:/icons/images/newlook24/003-addbook.png + + + Add Bookmark + + + + + + :/icons/images/newlook24/064-remsrc.png:/icons/images/newlook24/064-remsrc.png + + + Remove Bookmark + + + + + Modify Bookmark Description + + diff --git a/RedPandaIDE/systemconsts.h b/RedPandaIDE/systemconsts.h index 134407f5..6e35b577 100644 --- a/RedPandaIDE/systemconsts.h +++ b/RedPandaIDE/systemconsts.h @@ -47,6 +47,7 @@ #define DEV_AUTOLINK_FILE "autolink.json" #define DEV_SHORTCUT_FILE "shortcuts.json" #define DEV_TOOLS_FILE "tools.json" +#define DEV_BOOKMARK_FILE "bookmarks.json" #ifdef Q_OS_WIN # define PATH_SENSITIVITY Qt::CaseInsensitive diff --git a/RedPandaIDE/widgets/bookmarkmodel.cpp b/RedPandaIDE/widgets/bookmarkmodel.cpp index 0c8462e8..5087c670 100644 --- a/RedPandaIDE/widgets/bookmarkmodel.cpp +++ b/RedPandaIDE/widgets/bookmarkmodel.cpp @@ -1,6 +1,238 @@ #include "bookmarkmodel.h" +#include "../systemconsts.h" -BookmarkModel::BookmarkModel(QObject* parent):QAbstractItemModel(parent) +#include +#include +#include +#include +#include +#include +#include "../utils.h" + +BookmarkModel::BookmarkModel(QObject* parent):QAbstractTableModel(parent) { } + +QSet BookmarkModel::bookmarksInFile(const QString &filename) +{ + QSet lines; + foreach (const PBookmark& bookmark, mBookmarks) { + if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0) { + lines.insert(bookmark->line); + } + } + return lines; +} + +void BookmarkModel::addBookmark(const QString &filename, int line, const QString &description) +{ + Q_ASSERT(!isBookmarkExists(filename,line)); + PBookmark bookmark = std::make_shared(); + bookmark->filename = filename; + bookmark->line = line; + bookmark->description = description; + beginInsertRows(QModelIndex(),mBookmarks.count(),mBookmarks.count()); + mBookmarks.append(bookmark); + endInsertRows(); +} + +PBookmark BookmarkModel::bookmark(int i) +{ + return mBookmarks[i]; +} + +PBookmark BookmarkModel::bookmark(const QString &filename, int line) +{ + for (int i=0;ifilename.compare(filename, PATH_SENSITIVITY) == 0 + && bookmark->line == line) { + return bookmark; + } + } + return PBookmark(); +} + +bool BookmarkModel::removeBookmark(const QString &filename, int line) +{ + for (int i=0;ifilename.compare(filename, PATH_SENSITIVITY) == 0 + && bookmark->line == line) { + removeBookmarkAt(i); + return true; + } + } + return false; +} + +void BookmarkModel::clear() +{ + beginResetModel(); + mBookmarks.clear(); + endResetModel(); +} + +bool BookmarkModel::updateDescription(const QString &filename, int line, const QString &description) +{ + for (int i=0;ifilename.compare(filename, PATH_SENSITIVITY) == 0 + && bookmark->line == line) { + bookmark->description = description; + emit dataChanged(createIndex(i,0),createIndex(i,2)); + return true; + } + } + return false; +} + +void BookmarkModel::save(const QString &filename) +{ + QFile file(filename); + if (file.open(QFile::WriteOnly | QFile::Truncate)) { + QJsonArray array; + foreach (const PBookmark& bookmark, mBookmarks) { + QJsonObject obj; + obj["filename"]=bookmark->filename; + obj["line"]=bookmark->line; + obj["description"]=bookmark->description; + array.append(obj); + } + QJsonDocument doc; + doc.setArray(array); + if (file.write(doc.toJson())<0) { + throw FileError(tr("Save file '%1' failed.") + .arg(filename)); + } + } else { + throw FileError(tr("Can't open file '%1' for write.") + .arg(filename)); + } +} + +void BookmarkModel::load(const QString& filename) +{ + clear(); + QFile file(filename); + if (!file.exists()) + return; + if (file.open(QFile::ReadOnly)) { + QByteArray content = file.readAll(); + QJsonParseError error; + QJsonDocument doc(QJsonDocument::fromJson(content,&error)); + if (error.error != QJsonParseError::NoError) { + throw FileError(tr("Error in json file '%1':%2 : %3") + .arg(filename) + .arg(error.offset) + .arg(error.errorString())); + } + QJsonArray array = doc.array(); + for (int i=0;i=0;i--){ + PBookmark bookmark = mBookmarks[i]; + if (bookmark->filename == filename + && bookmark->line>=startLine) { + if (bookmark->line >= startLine+count) { + bookmark->line -= count; + emit dataChanged(createIndex(i,0),createIndex(i,2)); + } else { + removeBookmarkAt(i); + } + } + } +} + +void BookmarkModel::onFileInsertLines(const QString &filename, int startLine, int count) +{ + for (int i = mBookmarks.count()-1;i>=0;i--){ + PBookmark bookmark = mBookmarks[i]; + if (bookmark->filename == filename + && bookmark->line>=startLine) { + bookmark->line+=count; + emit dataChanged(createIndex(i,0),createIndex(i,2)); + } + } +} + +void BookmarkModel::removeBookmarkAt(int i) +{ + beginRemoveRows(QModelIndex(), i,i); + mBookmarks.removeAt(i); + endRemoveRows(); +} + +#ifdef QT_DEBUG +bool BookmarkModel::isBookmarkExists(const QString &filename, int line) +{ + foreach (const PBookmark& bookmark, mBookmarks) { + if (bookmark->filename.compare(filename, PATH_SENSITIVITY) == 0 + && bookmark->line == line) { + return true; + } + } + return false; +} + +int BookmarkModel::rowCount(const QModelIndex &) const +{ + return mBookmarks.count(); +} + +QVariant BookmarkModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + int row = index.row(); + PBookmark bookmark = mBookmarks[row]; + if (role == Qt::DisplayRole) { + switch(index.column()) { + case 0: + return bookmark->description; + case 1: + return bookmark->line; + case 2: + return bookmark->filename; + } + } + return QVariant(); +} + +int BookmarkModel::columnCount(const QModelIndex &) const +{ + return 3; +} + +QVariant BookmarkModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal) { + if (role == Qt::DisplayRole) { + switch(section) { + case 0: + return tr("Description"); + case 1: + return tr("Line"); + case 2: + return tr("Filename"); + } + } + } + return QVariant(); +} +#endif diff --git a/RedPandaIDE/widgets/bookmarkmodel.h b/RedPandaIDE/widgets/bookmarkmodel.h index 00831659..949a52d5 100644 --- a/RedPandaIDE/widgets/bookmarkmodel.h +++ b/RedPandaIDE/widgets/bookmarkmodel.h @@ -1,13 +1,54 @@ #ifndef BOOKMARKMODEL_H #define BOOKMARKMODEL_H -#include +#include +#include +#include -class BookmarkModel : public QAbstractItemModel +struct Bookmark { + QString filename; + int line; + QString description; +}; + +using PBookmark=std::shared_ptr; + +class BookmarkModel : public QAbstractTableModel { Q_OBJECT public: BookmarkModel(QObject* parent=nullptr); + QSet bookmarksInFile(const QString& filename); + void addBookmark(const QString&filename, int line, const QString& description); + PBookmark bookmark(int i); + PBookmark bookmark(const QString&filename, int line); + bool removeBookmark(const QString&filename, int line); + void clear(); + bool updateDescription(const QString&filename, int line, const QString& description); + void save(const QString& filename); + void load(const QString& filename); + void removeBookmarkAt(int i); +public slots: + void onFileDeleteLines(const QString& filename, int startLine, int count); + void onFileInsertLines(const QString& filename, int startLine, int count); +private: +#ifdef QT_DEBUG + bool isBookmarkExists(const QString&filename, int line); +#endif +private: + QList mBookmarks; + + // QAbstractItemModel interface +public: + int rowCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role) const override; + int columnCount(const QModelIndex &parent) const override; + + // QAbstractItemModel interface +public: + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; }; +using PBookmarkModel = std::shared_ptr; + #endif // BOOKMARKMODEL_H