From e098f652647648448bb4d740eb07d2ba01b0fe7a Mon Sep 17 00:00:00 2001 From: codeleep Date: Wed, 20 Mar 2024 19:26:36 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=A1=8C=E5=B0=BE?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E6=A6=82=E8=A6=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 支持鼠标移动显示 1. 修复多个项目打开不显示问题 2. 支持2023.3.5版本 回滚build.gradle --- build.gradle | 4 +- .../indi/bookmarkx/BookmarksManagePanel.java | 7 +- .../java/indi/bookmarkx/BookmarksManager.java | 65 ++++++--- .../action/BookmarkExportAction.java | 4 +- .../action/BookmarkImportAction.java | 4 +- .../bookmarkx/common/data/ArrayListTable.java | 73 ++++++++++ .../common/data/BookmarkArrayListTable.java | 86 +++++++++++ .../indi/bookmarkx/common/data/DataPool.java | 10 ++ .../common/data/index/ColumnIndex.java | 17 +++ .../common/data/index/SimpleColumnIndex.java | 28 ++++ .../global/BookmarkDocumentListener.java | 133 ++++++++++++++++++ .../bookmarkx/model/BookmarkNodeModel.java | 14 ++ .../indi/bookmarkx/model/po/BookmarkPO.java | 8 +- .../bookmarkx/painter/LineEndPainter.java | 66 +++++++++ .../indi/bookmarkx/tree/BookmarkTree.java | 62 +++++++- .../dialog/BookmarkCreatorDialog.java | 3 +- .../ui/pannel/ShowBookmarkTipPanel.java | 85 +++++++++++ src/main/resources/META-INF/plugin.xml | 4 + 18 files changed, 645 insertions(+), 28 deletions(-) create mode 100644 src/main/java/indi/bookmarkx/common/data/ArrayListTable.java create mode 100644 src/main/java/indi/bookmarkx/common/data/BookmarkArrayListTable.java create mode 100644 src/main/java/indi/bookmarkx/common/data/DataPool.java create mode 100644 src/main/java/indi/bookmarkx/common/data/index/ColumnIndex.java create mode 100644 src/main/java/indi/bookmarkx/common/data/index/SimpleColumnIndex.java create mode 100644 src/main/java/indi/bookmarkx/global/BookmarkDocumentListener.java create mode 100644 src/main/java/indi/bookmarkx/painter/LineEndPainter.java rename src/main/java/indi/bookmarkx/{ => ui}/dialog/BookmarkCreatorDialog.java (98%) create mode 100644 src/main/java/indi/bookmarkx/ui/pannel/ShowBookmarkTipPanel.java diff --git a/build.gradle b/build.gradle index f899f2a..174d0b1 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,7 @@ plugins { } group 'indi.bookmarkx' +version '1.1.1-SNAPSHOT' version '1.1.1' repositories { @@ -28,6 +29,7 @@ intellij { patchPluginXml { sinceBuild = '231.0' + changeNotes = "1.不再兼容 IDEA 2023 之前的版本\n2.添加书签导入导出功能" changeNotes = """ 1.不再兼容 IDEA 2023 之前的版本
2.添加书签导入导出功能 @@ -46,4 +48,4 @@ tasks.withType(JavaCompile).configureEach { test { useJUnitPlatform() -} \ No newline at end of file +} diff --git a/src/main/java/indi/bookmarkx/BookmarksManagePanel.java b/src/main/java/indi/bookmarkx/BookmarksManagePanel.java index c3983c5..dbb019c 100644 --- a/src/main/java/indi/bookmarkx/BookmarksManagePanel.java +++ b/src/main/java/indi/bookmarkx/BookmarksManagePanel.java @@ -4,6 +4,7 @@ import com.intellij.ui.JBColor; import com.intellij.ui.components.JBScrollPane; import com.intellij.util.ui.JBUI; +import indi.bookmarkx.common.data.BookmarkArrayListTable; import indi.bookmarkx.model.BookmarkNodeModel; import indi.bookmarkx.model.po.BookmarkPO; import indi.bookmarkx.tree.BookmarkTree; @@ -30,6 +31,7 @@ public class BookmarksManagePanel extends JPanel { private final Project project; + private final BookmarkArrayListTable bookmarkArrayListTable; /** * 标记 tree 是否已经从持久化文件加载完成 */ @@ -41,6 +43,8 @@ private BookmarksManagePanel(Project project) { this.project = project; + bookmarkArrayListTable = BookmarkArrayListTable.getInstance(project); + tree = new BookmarkTree(project); setLayout(new BorderLayout()); @@ -178,7 +182,8 @@ protected Void doInBackground() throws Exception { jepDesc.setText(""); } }); - + BookmarkArrayListTable bookmarkArrayListTable = BookmarkArrayListTable.getInstance(project); + bookmarkArrayListTable.initData(tree); treeLoaded = true; } } diff --git a/src/main/java/indi/bookmarkx/BookmarksManager.java b/src/main/java/indi/bookmarkx/BookmarksManager.java index 1c3704d..5574ce9 100644 --- a/src/main/java/indi/bookmarkx/BookmarksManager.java +++ b/src/main/java/indi/bookmarkx/BookmarksManager.java @@ -6,9 +6,13 @@ import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; -import indi.bookmarkx.dialog.BookmarkCreatorDialog; +import indi.bookmarkx.common.data.BookmarkArrayListTable; +import indi.bookmarkx.ui.dialog.BookmarkCreatorDialog; import indi.bookmarkx.model.BookmarkConverter; import indi.bookmarkx.model.BookmarkNodeModel; +import indi.bookmarkx.painter.LineEndPainter; +import indi.bookmarkx.tree.BookmarkTree; +import indi.bookmarkx.tree.BookmarkTreeNode; import indi.bookmarkx.utils.PersistenceUtil; import org.jetbrains.annotations.NotNull; @@ -25,8 +29,11 @@ public final class BookmarksManager { private BookmarksManagePanel toolWindowRootPanel; + private BookmarkArrayListTable bookmarkArrayListTable; + public BookmarksManager(Project project) { this.project = project; + bookmarkArrayListTable = BookmarkArrayListTable.getInstance(project); } public static BookmarksManager getInstance(Project project) { @@ -46,26 +53,48 @@ public void createBookRemark(Project project, Editor editor, VirtualFile file) { // 获取行号 int line = caretModel.getLogicalPosition().line; int column = caretModel.getLogicalPosition().column; - // 获取选中文本 - String selectedText = caretModel.getCurrentCaret().getSelectedText(); - selectedText = selectedText == null ? "" : (" " + selectedText + " "); - - String uuid = UUID.randomUUID().toString(); + BookmarkNodeModel bookmarkNodeModel = LineEndPainter.findLine(BookmarkArrayListTable.getInstance(project).getOnlyIndex(file.getPath()), line); + String defaultName = file.getName(); + String defaultDesc = null; + boolean add = true; + if (bookmarkNodeModel == null) { + add = true; + // 获取选中文本 + String selectedText = caretModel.getCurrentCaret().getSelectedText(); + defaultDesc = selectedText == null ? "" : (" " + selectedText + " "); + String uuid = UUID.randomUUID().toString(); + bookmarkNodeModel = new BookmarkNodeModel(); + bookmarkNodeModel.setUuid(uuid); + bookmarkNodeModel.setLine(line); + bookmarkNodeModel.setColumn(column); + bookmarkNodeModel.setIcon(file.getFileType().getIcon()); + bookmarkNodeModel.setIcon(file.getFileType().getIcon()); + bookmarkNodeModel.setOpenFileDescriptor(new OpenFileDescriptor(project, file, line, column)); + }else { + add = false; + defaultName = bookmarkNodeModel.getName(); + defaultDesc = bookmarkNodeModel.getDesc(); + } + final BookmarkNodeModel finalBookmarkNodeModel = bookmarkNodeModel; + final boolean addFlag = add; new BookmarkCreatorDialog(project) - .defaultName(file.getName()) - .defaultDesc(selectedText) + .defaultName(defaultName) + .defaultDesc(defaultDesc) .showAndCallback((name, desc) -> { - BookmarkNodeModel bookmarkModel = new BookmarkNodeModel(); - bookmarkModel.setUuid(uuid); - bookmarkModel.setLine(line); - bookmarkModel.setColumn(column); - bookmarkModel.setIcon(file.getFileType().getIcon()); - bookmarkModel.setName(name); - bookmarkModel.setIcon(file.getFileType().getIcon()); - bookmarkModel.setOpenFileDescriptor(new OpenFileDescriptor(project, file, line, column)); - bookmarkModel.setDesc(desc); - submitCreateBookRemark(bookmarkModel, editor); + finalBookmarkNodeModel.setName(name); + finalBookmarkNodeModel.setDesc(desc); + bookmarkArrayListTable.insert(finalBookmarkNodeModel); + if (addFlag) { + submitCreateBookRemark(finalBookmarkNodeModel, editor); + }else { + if (!Objects.isNull(toolWindowRootPanel)) { + BookmarkTree tree = toolWindowRootPanel.tree(); + BookmarkTreeNode nodeByModel = tree.getNodeByModel(finalBookmarkNodeModel); + tree.getModel().nodeChanged(nodeByModel); + } + } + }); } diff --git a/src/main/java/indi/bookmarkx/action/BookmarkExportAction.java b/src/main/java/indi/bookmarkx/action/BookmarkExportAction.java index ce7b867..3eae1bf 100644 --- a/src/main/java/indi/bookmarkx/action/BookmarkExportAction.java +++ b/src/main/java/indi/bookmarkx/action/BookmarkExportAction.java @@ -9,12 +9,12 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.ToolWindowId; import indi.bookmarkx.MyPersistent; import indi.bookmarkx.common.I18N; import indi.bookmarkx.model.po.BookmarkPO; import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import java.io.File; @@ -87,7 +87,7 @@ private void stateTranslate(BookmarkPO po) { private void stateTranslate(BookmarkPO po, String dir) { String virtualFilePath = po.getVirtualFilePath(); - if (StringUtils.isNotEmpty(virtualFilePath)) { + if (StringUtil.isNotEmpty(virtualFilePath)) { po.setVirtualFilePath(virtualFilePath.replace(dir, "$PROJECT_DIR$")); } if (CollectionUtils.isNotEmpty(po.getChildren())) { diff --git a/src/main/java/indi/bookmarkx/action/BookmarkImportAction.java b/src/main/java/indi/bookmarkx/action/BookmarkImportAction.java index 6efd929..ade18fb 100644 --- a/src/main/java/indi/bookmarkx/action/BookmarkImportAction.java +++ b/src/main/java/indi/bookmarkx/action/BookmarkImportAction.java @@ -8,13 +8,13 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import indi.bookmarkx.BookmarksManager; import indi.bookmarkx.MyPersistent; import indi.bookmarkx.common.I18N; import indi.bookmarkx.model.po.BookmarkPO; import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import java.io.IOException; @@ -69,7 +69,7 @@ private void stateTranslate(BookmarkPO po) { private void stateTranslate(BookmarkPO po, String dir) { String virtualFilePath = po.getVirtualFilePath(); - if (StringUtils.isNotEmpty(virtualFilePath)) { + if (StringUtil.isNotEmpty(virtualFilePath)) { po.setVirtualFilePath(virtualFilePath.replace("$PROJECT_DIR$", dir)); } if (CollectionUtils.isNotEmpty(po.getChildren())) { diff --git a/src/main/java/indi/bookmarkx/common/data/ArrayListTable.java b/src/main/java/indi/bookmarkx/common/data/ArrayListTable.java new file mode 100644 index 0000000..dcc6655 --- /dev/null +++ b/src/main/java/indi/bookmarkx/common/data/ArrayListTable.java @@ -0,0 +1,73 @@ +package indi.bookmarkx.common.data; + +import indi.bookmarkx.common.data.index.SimpleColumnIndex; + +import java.util.*; +import java.util.function.Function; + +/** + * @author: codeleep + * @createTime: 2024/03/20 14:58 + * @description: 数组表格 + */ +public class ArrayListTable implements DataPool{ + + protected List dataList; + + protected final HashMap>> columnIndices = new HashMap<>(); + + public ArrayListTable(List arrayList, List> functions) { + this.dataList = arrayList; + functions.forEach(this::addColumIndex); + } + + protected void addColumIndex(Function function) { + SimpleColumnIndex> index = new SimpleColumnIndex<>(); + dataList.forEach(data -> { + try { + saveHunt(data, function, (SimpleColumnIndex>) index); + }catch (Exception e) { + + } + }); + columnIndices.put(function, index); + } + + public List getOnlyIndex(Object key){ + for (SimpleColumnIndex> index: columnIndices.values()) { + Set hunt = index.hunt(String.valueOf(key)); + if (hunt != null) { + return new ArrayList<>(hunt); + } + } + return null; + } + + public void insert(T data){ + columnIndices.forEach((function, index) -> { + saveHunt(data, function, (SimpleColumnIndex>) index); + }); + this.dataList.add(data); + } + + private void saveHunt(T data, Function function, SimpleColumnIndex> index) { + String key = String.valueOf(function.apply(data)); + Set hunt = index.hunt(key); + if (hunt == null) { + hunt = new HashSet<>(); + index.drawUp(key, hunt); + } + hunt.add(data); + } + + public void delete(T data) { + columnIndices.forEach((function, index) -> { + String key = String.valueOf(function.apply(data)); + Set hunt = index.hunt(key); + if (hunt != null) { + hunt.remove(data); + } + }); + this.dataList.remove(data); + } +} diff --git a/src/main/java/indi/bookmarkx/common/data/BookmarkArrayListTable.java b/src/main/java/indi/bookmarkx/common/data/BookmarkArrayListTable.java new file mode 100644 index 0000000..d224913 --- /dev/null +++ b/src/main/java/indi/bookmarkx/common/data/BookmarkArrayListTable.java @@ -0,0 +1,86 @@ +package indi.bookmarkx.common.data; + +import com.intellij.openapi.components.Service; +import com.intellij.openapi.project.Project; +import indi.bookmarkx.model.AbstractTreeNodeModel; +import indi.bookmarkx.model.BookmarkConverter; +import indi.bookmarkx.model.BookmarkNodeModel; +import indi.bookmarkx.model.po.BookmarkPO; +import indi.bookmarkx.tree.BookmarkTree; +import indi.bookmarkx.tree.BookmarkTreeNode; + +import javax.swing.tree.TreeNode; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +/** + * @author: codeleep + * @createTime: 2024/03/20 14:58 + * @description: 数组表格 + */ +@Service(Service.Level.PROJECT) +public final class BookmarkArrayListTable extends ArrayListTable { + + private final Project project; + + public static BookmarkArrayListTable getInstance(Project project) { + return project.getService(BookmarkArrayListTable.class); + } + + public BookmarkArrayListTable(Project project) { + super(new ArrayList<>(), getColumnIndexFunctions()); + this.project = project; + } + + public void initData(BookmarkTree bookmarkPO) { + this.dataList = treeToList(bookmarkPO, new ArrayList<>()); + columnIndices.keySet().forEach(super::addColumIndex); + } + + private static List> getColumnIndexFunctions() { + ArrayList> functions = new ArrayList<>(); + functions.add(lineColumnIndex()); + functions.add(uuIdColumnIndex()); + return functions; + } + + private static Function lineColumnIndex() { + return bookmarkPO -> bookmarkPO.getOpenFileDescriptor().getFile().getPath(); + } + + private static Function uuIdColumnIndex() { + return BookmarkNodeModel::getUuid; + } + + + private List treeToList(BookmarkTree bookmarkTree,List list) { + if (bookmarkTree == null) { + return list; + } + BookmarkTreeNode bookmarkTreeNode = (BookmarkTreeNode)bookmarkTree.getModel().getRoot(); + if (bookmarkTreeNode == null) { + return list; + } + toList(bookmarkTreeNode, list); + return list; + } + + private static void toList(BookmarkTreeNode node, List list) { + int childCount = node.getChildCount(); + AbstractTreeNodeModel model = (AbstractTreeNodeModel) node.getUserObject(); + if (0 == childCount) { + return; + } + for (int i = 0; i < childCount; i++) { + BookmarkTreeNode treeNode = (BookmarkTreeNode) node.getChildAt(i); + Object userObject = treeNode.getUserObject(); + if (userObject instanceof BookmarkNodeModel) { + list.add((BookmarkNodeModel)userObject); + } + toList(treeNode, list); + } + } + + +} diff --git a/src/main/java/indi/bookmarkx/common/data/DataPool.java b/src/main/java/indi/bookmarkx/common/data/DataPool.java new file mode 100644 index 0000000..bec47b8 --- /dev/null +++ b/src/main/java/indi/bookmarkx/common/data/DataPool.java @@ -0,0 +1,10 @@ +package indi.bookmarkx.common.data; + +/** + * @author: codeleep + * @createTime: 2024/03/20 14:58 + * @description: 数据池 + */ +public interface DataPool { + +} diff --git a/src/main/java/indi/bookmarkx/common/data/index/ColumnIndex.java b/src/main/java/indi/bookmarkx/common/data/index/ColumnIndex.java new file mode 100644 index 0000000..3d08115 --- /dev/null +++ b/src/main/java/indi/bookmarkx/common/data/index/ColumnIndex.java @@ -0,0 +1,17 @@ +package indi.bookmarkx.common.data.index; + +import java.util.List; + +/** + * @author: codeleep + * @createTime: 2024/03/20 15:00 + * @description: 列索引 + */ +public interface ColumnIndex { + + V hunt(K key); + + void drawUp(K key, V value); + + void drawDown(K key); +} diff --git a/src/main/java/indi/bookmarkx/common/data/index/SimpleColumnIndex.java b/src/main/java/indi/bookmarkx/common/data/index/SimpleColumnIndex.java new file mode 100644 index 0000000..6a4dcd7 --- /dev/null +++ b/src/main/java/indi/bookmarkx/common/data/index/SimpleColumnIndex.java @@ -0,0 +1,28 @@ +package indi.bookmarkx.common.data.index; + +import java.util.HashMap; + +/** + * @author: codeleep + * @createTime: 2024/03/20 15:01 + * @description: 简单列索引.以hashMap为底层存储 + */ +public class SimpleColumnIndex implements ColumnIndex{ + + private final HashMap indexMap = new HashMap<>(); + + @Override + public V hunt(String key) { + return indexMap.get(key); + } + + @Override + public void drawUp(String key, V value) { + indexMap.put(key, value); + } + + @Override + public void drawDown(String key) { + indexMap.remove(key); + } +} diff --git a/src/main/java/indi/bookmarkx/global/BookmarkDocumentListener.java b/src/main/java/indi/bookmarkx/global/BookmarkDocumentListener.java new file mode 100644 index 0000000..c66cf9a --- /dev/null +++ b/src/main/java/indi/bookmarkx/global/BookmarkDocumentListener.java @@ -0,0 +1,133 @@ +package indi.bookmarkx.global; + +import com.intellij.diff.util.LineRange; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.event.DocumentEvent; +import com.intellij.openapi.editor.event.DocumentListener; +import com.intellij.openapi.editor.impl.EditorFactoryImpl; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.fileEditor.OpenFileDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import indi.bookmarkx.BookmarksManager; +import indi.bookmarkx.MyPersistent; +import indi.bookmarkx.common.data.BookmarkArrayListTable; +import indi.bookmarkx.model.BookmarkNodeModel; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author: codeleep + * @createTime: 2024/03/20 19:44 + * @description: 文档变化监听 + */ +public class BookmarkDocumentListener implements DocumentListener { + + private static final Logger LOG = Logger.getInstance(MyPersistent.class); + + @Override + public void beforeDocumentChange(@NotNull DocumentEvent event) { + try { + Document document = event.getDocument(); + CharSequence newFragment = event.getNewFragment(); + CharSequence oldFragment = event.getOldFragment(); + // 获取行变化 + String newStr = String.valueOf(newFragment); + String oldStr = String.valueOf(oldFragment); + int newLineCount = StringUtil.countChars(newStr, '\n'); + int oldLineCount = StringUtil.countChars(oldStr, '\n'); + if ((newLineCount <= 0 && oldLineCount <= 0) || newLineCount == oldLineCount){ + return; + } + VirtualFile virtualFile = FileDocumentManager.getInstance().getFile(document); + if (virtualFile == null) { + return; + } + Editor editor = getEditor(document); + if (editor == null) { + return; + } + Project project = editor.getProject(); + if (project == null) { + return; + } + BookmarkArrayListTable bookmarkArrayListTable = BookmarkArrayListTable.getInstance(project); + List onlyIndex = bookmarkArrayListTable.getOnlyIndex(virtualFile.getPath()); + // 空的直接返回 + if (onlyIndex == null || onlyIndex.isEmpty()) { + return; + } + // 计算行变化 + int offset = event.getOffset(); + // 变化所在行 + int startLineNumber = 0; + int endLineNumber = 0; + boolean isAdd = true; + if (newLineCount > oldLineCount) { + isAdd = true; + startLineNumber = document.getLineNumber(offset) + 1; + endLineNumber = startLineNumber + newLineCount - oldLineCount; + }else { + isAdd = false; + endLineNumber = document.getLineNumber(offset) + 1; + startLineNumber = endLineNumber - oldLineCount + newLineCount; + } + LineRange lineRange = new LineRange(startLineNumber, endLineNumber); + perceivedLineChange(project, virtualFile, onlyIndex, lineRange, isAdd); + }catch (Exception e) { + LOG.info("perceivedLineChange error", e); + } + } + + + private void perceivedLineChange(Project project, VirtualFile virtualFile, List list, LineRange lineRange, boolean isAdd) { + if (list == null || list.isEmpty()) { + return; + } + BookmarkArrayListTable bookmarkArrayListTable = BookmarkArrayListTable.getInstance(project); + BookmarksManager bookmarksManager = BookmarksManager.getInstance(project); + List removeList = new ArrayList<>(); + for (BookmarkNodeModel node : list) { + if (node == null){ + continue; + } + int positionLine = Integer.parseInt(String.valueOf(node.getLine())); + int rowGap = lineRange.end - lineRange.start; + int changeLine = lineRange.start; + if(isAdd) { + if (positionLine + 1 < changeLine) { + continue; + } + node.setLine(positionLine + rowGap); + node.setOpenFileDescriptor(new OpenFileDescriptor(project, virtualFile, positionLine + rowGap, 0)); + }else { + if (positionLine <= changeLine) { + continue; + } + if (positionLine < lineRange.end && positionLine > lineRange.start) { + removeList.add(node); + continue; + } + node.setLine(positionLine - rowGap); + node.setOpenFileDescriptor(new OpenFileDescriptor(project, virtualFile, positionLine - rowGap, 0)); + } + removeList.forEach(bookmarkArrayListTable::delete); + bookmarksManager.persistentSave(); + } + } + + private Editor getEditor(Document document) { + Editor[] editors = EditorFactoryImpl.getInstance().getEditors(document); + if (editors.length >= 1){ + return editors[0]; + } + return null; + } + +} diff --git a/src/main/java/indi/bookmarkx/model/BookmarkNodeModel.java b/src/main/java/indi/bookmarkx/model/BookmarkNodeModel.java index a76f995..84a36a5 100644 --- a/src/main/java/indi/bookmarkx/model/BookmarkNodeModel.java +++ b/src/main/java/indi/bookmarkx/model/BookmarkNodeModel.java @@ -3,6 +3,7 @@ import com.intellij.openapi.fileEditor.OpenFileDescriptor; import javax.swing.*; +import java.util.Objects; /** * 书签数据模型 @@ -32,6 +33,19 @@ public class BookmarkNodeModel extends AbstractTreeNodeModel { public BookmarkNodeModel() { } + @Override + public int hashCode() { + return Objects.hash(uuid); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BookmarkNodeModel yourClass = (BookmarkNodeModel) o; + return uuid.equals(yourClass.uuid); + } + @Override public String getName() { diff --git a/src/main/java/indi/bookmarkx/model/po/BookmarkPO.java b/src/main/java/indi/bookmarkx/model/po/BookmarkPO.java index 9a2af45..7e2c2d8 100644 --- a/src/main/java/indi/bookmarkx/model/po/BookmarkPO.java +++ b/src/main/java/indi/bookmarkx/model/po/BookmarkPO.java @@ -1,7 +1,10 @@ package indi.bookmarkx.model.po; import javax.xml.bind.annotation.XmlRootElement; +import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.stream.Collectors; /** * 书签持久化对象
@@ -34,10 +37,13 @@ public class BookmarkPO { */ private String virtualFilePath; - private List children; + private List children = new ArrayList<>(); public List getChildren() { + List list = children.stream().distinct().collect(Collectors.toList()); + children.clear(); + children.addAll(list); return children; } diff --git a/src/main/java/indi/bookmarkx/painter/LineEndPainter.java b/src/main/java/indi/bookmarkx/painter/LineEndPainter.java new file mode 100644 index 0000000..9a5b457 --- /dev/null +++ b/src/main/java/indi/bookmarkx/painter/LineEndPainter.java @@ -0,0 +1,66 @@ +package indi.bookmarkx.painter; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.EditorLinePainter; +import com.intellij.openapi.editor.LineExtensionInfo; +import com.intellij.openapi.editor.markup.TextAttributes; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.JBColor; +import indi.bookmarkx.MyPersistent; +import indi.bookmarkx.common.data.BookmarkArrayListTable; +import indi.bookmarkx.model.BookmarkNodeModel; +import indi.bookmarkx.model.po.BookmarkPO; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +/** + * @author: codeleep + * @createTime: 2023/12/14 23:37 + * @description: + */ +public class LineEndPainter extends EditorLinePainter { + + private static final Logger LOG = Logger.getInstance(MyPersistent.class); + + private BookmarkNodeModel bookmarkNodeModel; + + private BookmarkArrayListTable bookmarkArrayListTable; + + private Project project; + + @Override + public Collection getLineExtensions(Project project, VirtualFile virtualFile, int i) { + if (this.project != project || bookmarkArrayListTable == null) { + this.project = project; + bookmarkArrayListTable = BookmarkArrayListTable.getInstance(project); + } + List result = new ArrayList<>(); + try { + List onlyIndex = bookmarkArrayListTable.getOnlyIndex(virtualFile.getPath()); + bookmarkNodeModel = LineEndPainter.findLine(onlyIndex, i); + if (bookmarkNodeModel == null) { + return null; + } + result.add(new LineExtensionInfo(String.format("// %s", bookmarkNodeModel.getName()), new TextAttributes(null, null, JBColor.GRAY, null, Font.PLAIN))); + return result; + } catch (Exception e) { + LOG.error("渲染行尾注释失败 path:"+virtualFile.getPath(), e); + } + return null; + } + + public static BookmarkNodeModel findLine(List list, int i) { + if (list == null || list.isEmpty()){ + return null; + } + Optional bookmarkNodeModel1 = list.stream().filter(bookmarkNodeModel -> bookmarkNodeModel.getOpenFileDescriptor().getLine() == i).findFirst(); + return bookmarkNodeModel1.orElse(null); + } + +} + diff --git a/src/main/java/indi/bookmarkx/tree/BookmarkTree.java b/src/main/java/indi/bookmarkx/tree/BookmarkTree.java index d7b2dce..120e4cd 100644 --- a/src/main/java/indi/bookmarkx/tree/BookmarkTree.java +++ b/src/main/java/indi/bookmarkx/tree/BookmarkTree.java @@ -10,9 +10,12 @@ import com.intellij.ui.TreeSpeedSearch; import com.intellij.ui.treeStructure.Tree; import indi.bookmarkx.common.I18N; -import indi.bookmarkx.dialog.BookmarkCreatorDialog; +import indi.bookmarkx.common.data.BookmarkArrayListTable; +import indi.bookmarkx.ui.dialog.BookmarkCreatorDialog; +import indi.bookmarkx.model.AbstractTreeNodeModel; import indi.bookmarkx.model.BookmarkNodeModel; import indi.bookmarkx.model.GroupNodeModel; +import indi.bookmarkx.ui.pannel.ShowBookmarkTipPanel; import org.apache.commons.lang3.Validate; import org.jsoup.internal.StringUtil; @@ -25,6 +28,7 @@ import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; import java.util.List; import java.util.*; import java.util.stream.Collectors; @@ -48,6 +52,8 @@ public class BookmarkTree extends Tree { private Project project; + private BookmarkArrayListTable bookmarkArrayListTable; + public BookmarkTree(Project project) { super(); initData(project); @@ -67,6 +73,7 @@ private void initView() { private void initData(Project project) { this.project = project; + bookmarkArrayListTable = BookmarkArrayListTable.getInstance(project); BookmarkTreeNode root = new BookmarkTreeNode(new GroupNodeModel(project.getName())); model = new DefaultTreeModel(root); @@ -126,6 +133,54 @@ private void initTreeListeners() { } }); + addMouseMotionListener(new MouseMotionAdapter() { + @Override + public void mouseMoved(MouseEvent e) { + // Get the selected node + TreePath path = getPathForLocation(e.getX(), e.getY()); + if (path != null) { + // Show tooltip for the node + showToolTip(getToolTipText(e), e); + } else { + if (this.lastPopup != null) { + lastPopup.hide(); + } + } + } + + private AbstractTreeNodeModel getToolTipText(MouseEvent e) { + TreePath path = getPathForLocation(e.getX(), e.getY()); + if (path != null) { + BookmarkTreeNode selectedNode = (BookmarkTreeNode) path.getLastPathComponent(); + if (selectedNode != null) { + return (AbstractTreeNodeModel) selectedNode.getUserObject(); + } + } + return null; + } + + private Popup lastPopup; + private AbstractTreeNodeModel lastAbstractTreeNodeModel; + private void showToolTip(AbstractTreeNodeModel abstractTreeNodeModel, MouseEvent e) { + if (abstractTreeNodeModel == null) { + return; + } + if (lastAbstractTreeNodeModel == abstractTreeNodeModel) { + return; + } + Point adjustedLocation = new Point(e.getLocationOnScreen().x + 10, e.getLocationOnScreen().y + 20); // Adjust position + PopupFactory popupFactory = PopupFactory.getSharedInstance(); + if (this.lastPopup != null) { + lastPopup.hide(); + } + lastAbstractTreeNodeModel = abstractTreeNodeModel; + lastPopup = popupFactory.getPopup(e.getComponent(), new ShowBookmarkTipPanel(abstractTreeNodeModel), adjustedLocation.x, adjustedLocation.y); + lastPopup.show(); + } + + }); + + // 鼠标点击事件 addMouseListener(new MouseAdapter() { @Override @@ -181,6 +236,7 @@ private void initContextMenu() { .showAndCallback((name, desc) -> { nodeModel.setName(name); nodeModel.setDesc(desc); + bookmarkArrayListTable.insert(nodeModel); BookmarkTree.this.model.nodeChanged(selectedNode); }); } @@ -304,6 +360,10 @@ public void add(BookmarkTreeNode node) { */ public void remove(BookmarkTreeNode node) { model.removeNodeFromParent(node); + Object userObject = node.getUserObject(); + if (userObject instanceof BookmarkNodeModel) { + bookmarkArrayListTable.delete((BookmarkNodeModel) node.getUserObject()); + } removeFromCache(node); } diff --git a/src/main/java/indi/bookmarkx/dialog/BookmarkCreatorDialog.java b/src/main/java/indi/bookmarkx/ui/dialog/BookmarkCreatorDialog.java similarity index 98% rename from src/main/java/indi/bookmarkx/dialog/BookmarkCreatorDialog.java rename to src/main/java/indi/bookmarkx/ui/dialog/BookmarkCreatorDialog.java index 3ea1da2..1b956c2 100644 --- a/src/main/java/indi/bookmarkx/dialog/BookmarkCreatorDialog.java +++ b/src/main/java/indi/bookmarkx/ui/dialog/BookmarkCreatorDialog.java @@ -1,4 +1,4 @@ -package indi.bookmarkx.dialog; +package indi.bookmarkx.ui.dialog; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.event.DocumentListener; @@ -10,7 +10,6 @@ import com.intellij.ui.components.JBScrollPane; import com.intellij.util.ui.JBDimension; import com.intellij.util.ui.JBUI; -import indi.bookmarkx.BookmarksManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/indi/bookmarkx/ui/pannel/ShowBookmarkTipPanel.java b/src/main/java/indi/bookmarkx/ui/pannel/ShowBookmarkTipPanel.java new file mode 100644 index 0000000..8a70118 --- /dev/null +++ b/src/main/java/indi/bookmarkx/ui/pannel/ShowBookmarkTipPanel.java @@ -0,0 +1,85 @@ +package indi.bookmarkx.ui.pannel; + +import com.intellij.ui.EditorTextField; +import com.intellij.ui.components.JBPanel; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.util.ui.JBDimension; +import com.intellij.util.ui.JBUI; +import indi.bookmarkx.model.AbstractTreeNodeModel; +import indi.bookmarkx.model.BookmarkNodeModel; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; + +/** + * @author: codeleep + * @createTime: 2024/03/21 11:49 + * @description: + */ +public class ShowBookmarkTipPanel extends JBPanel { + + private final EditorTextField tfName = new EditorTextField(); + private final EditorTextField tfDesc = new EditorTextField(); + + public ShowBookmarkTipPanel(@NotNull AbstractTreeNodeModel abstractTreeNodeModel) { + tfName.setText(abstractTreeNodeModel.getName()); + if (abstractTreeNodeModel.isBookmark()) { + tfDesc.setText(((BookmarkNodeModel)abstractTreeNodeModel).getDesc()); + } + init(abstractTreeNodeModel); + } + + + private void init(@NotNull AbstractTreeNodeModel abstractTreeNodeModel) { + setLayout(new GridBagLayout()); + tfName.setPlaceholder("输入展示在标签上的文本"); + tfName.setEnabled(false); + tfDesc.setPlaceholder("输入对标签的详细描述"); + tfDesc.setEnabled(false); + tfDesc.setOneLineMode(false); + tfDesc.setBorder(JBUI.Borders.empty()); + // 创建 GridBagConstraints 对象 + GridBagConstraints constraints = new GridBagConstraints(); + constraints.fill = GridBagConstraints.BOTH; + constraints.insets = JBUI.insets(5); + + // 第一行第一列 + JLabel lbName = new JLabel("标签"); + constraints.gridx = 0; + constraints.gridy = 0; + constraints.weightx = 0; + constraints.weighty = 0; + add(lbName, constraints); + + // 第一行第二列 + constraints.gridx = 1; + constraints.gridy = 0; + constraints.weightx = 1; + constraints.weighty = 0; + add(tfName, constraints); + + if (abstractTreeNodeModel.isBookmark()) { + // 第二行第一列 + JLabel lbDesc = new JLabel("描述"); + constraints.gridx = 0; + constraints.gridy = 1; + constraints.weightx = 0; + constraints.weighty = 1; + add(lbDesc, constraints); + + // 第二行第二列 + JBScrollPane scrollPane = new JBScrollPane(tfDesc); + scrollPane.setPreferredSize(new JBDimension(400, 150)); + scrollPane.setBorder(JBUI.Borders.empty()); + + constraints.gridx = 1; + constraints.gridy = 1; + constraints.weightx = 1; + constraints.weighty = 1; + add(scrollPane, constraints); + } + + } + +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 36d4001..ff5fab0 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -21,6 +21,10 @@ + + + + From 2d1c478b920942cbba1b64a4c51e279f0937855a Mon Sep 17 00:00:00 2001 From: codeleep Date: Sun, 24 Mar 2024 16:00:48 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E6=98=BE=E7=A4=BA=E4=BD=9C=E8=80=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: local-li --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 174d0b1..a45a879 100644 --- a/build.gradle +++ b/build.gradle @@ -46,6 +46,7 @@ tasks.withType(JavaCompile).configureEach { options.compilerArgs << '-Xlint:-deprecation' } + test { useJUnitPlatform() } From 42c822c6da98f4a0079b6ad0b25ee479ea1918d2 Mon Sep 17 00:00:00 2001 From: codeleep Date: Sun, 24 Mar 2024 16:04:11 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E6=98=BE=E7=A4=BA=E4=BD=9C=E8=80=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: codeleep --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index de4590a..a050dc4 100644 --- a/build.gradle +++ b/build.gradle @@ -35,6 +35,7 @@ patchPluginXml { } + tasks.named('initializeIntelliJPlugin') { enabled = false }