IntelliJ Plugin - Action 获取 Tree 上节点
28 Jul 2022开发插件时使用 SimpleTree 来做数据的展示,SimpleTree 上可以配置节点上的右键菜单:
// 代码引用自 IDEA 社区版源码
// com.intellij.openapi.externalSystem.view.ExternalProjectsViewImpl#initTree
myTree.addMouseListener(new PopupHandler() {
@Override
public void invokePopup(final Component comp, final int x, final int y) {
final String id = getMenuId(getSelectedNodes(ExternalSystemNode.class));
if (id != null) {
final ActionGroup actionGroup = (ActionGroup)actionManager.getAction(id);
if (actionGroup != null) {
actionManager.createActionPopupMenu(ExternalProjectsViewImpl.this.getName(), actionGroup).getComponent().show(comp, x, y);
}
}
}
@Nullable
private String getMenuId(Collection<? extends ExternalSystemNode> nodes) {
String id = null;
for (ExternalSystemNode node : nodes) {
String menuId = node.getMenuId();
if (menuId == null) {
return null;
}
if (id == null) {
id = menuId;
}
else if (!id.equals(menuId)) {
return null;
}
}
return id;
}
});
接下来的问题就是,在 Action 里如何获取右击时被选中的节点?继续查看 IDEA 源码,可以看到 Gradle 插件里最终可以执行的任务的 Node 是 RunConfigurationNode,该节点的 MenuId 是 ExternalSystemView.RunConfigurationMenu
,最终找到相关的 Action,例如 EditExternalSystemRunConfigurationAction,里面获取选中节点是这样实现:
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
// 省略
final List<ExternalSystemNode> selectedNodes = e.getData(ExternalSystemDataKeys.SELECTED_NODES);
// 省略
}
那么 AnActionEvent 的数据又是谁放的呢?使用 ExternalSystemDataKeys.SELECTED_NODES
做关键字继续查找,会发现是在 ExternalProjectsViewImpl 实现的 com.intellij.openapi.actionSystem.DataProvider#getData
接口里使用:
@Nullable
@Override
public Object getData(@NotNull @NonNls String dataId) {
// 省略
if (ExternalSystemDataKeys.SELECTED_NODES.is(dataId)) return getSelectedNodes(ExternalSystemNode.class);
// 省略
return super.getData(dataId);
}
阅读 DataProvider 接口的注释,可以知道 AnActionEvent 获取 Data 会在 UI 树上向上遍历,如果 UI 组件实现了 DataProvider 接口就会询问其能否返回对应的数据,如果有组件返回了非 null 数据那么查找就结束。
Gradle 插件的实现里 ExternalProjectsViewImpl 是最外层的界面组件,所以在这里实现 DataProvider 接口来提供数据。我们也可以继承 SimpleTree 来实现 DataProvider 接口提供数据。