IDEA 插件开发

 

IDEA 插件开发

----------------------------------------------------------------------------------------

一、PropertiesComponent.getInstance(project):临时储存数据,适用于application级别和project级别

PropertiesComponent.getInstance(project).setValue("kwy", "value");
PropertiesComponent.getInstance(project).getValue("key");

  

二、FileDocumentManager.getInstance().saveAllDocuments():保存文档记录

FileDocumentManager.getInstance().saveAllDocuments();

  

三、创建底边toolwindow

1、继承Executor类
public class MyExecutor extends Executor{}
2、配置extensions
  <extensions defaultExtensionNs="com.intellij">
    <executor implementation="mybatis.log.action.MyExecutor" id="MyExecutor"/>
  </extensions>
Disposer.register(project, executor)

3、创建RunnerLayoutUi
 final RunnerLayoutUi.Factory factory = RunnerLayoutUi.Factory.getInstance(e.getProject());
        final RunnerLayoutUi layoutUi = factory.create("SQL", "SQL", "SQL", e.getProject());
4、创建RunContentDescriptor:
 return new RunContentDescriptor(new RunProfile() {
            @Nullable
            @Override
            public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment executionEnvironment) throws ExecutionException {
                return null;
            }

            @Override
            public String getName() {
                //第一层名称显示
                return "Sql";
            }

            @Nullable
            @Override
            public Icon getIcon() {
                return null;
            }
        }, new DefaultExecutionResult(), layoutUi);
Disposer.register(descriptor, this);
Disposer.register(content, console);

5、展示工具ExecutionManager.getInstance(e.getProject()).getContentManager().showRunContent(executor, descriptor);

  

四、在toolwindow添加控制台(打印台)

1、    TextConsoleBuilder consoleBuilder = TextConsoleBuilderFactory.getInstance().createBuilder(e.getProject());
        ConsoleView console = consoleBuilder.getConsole();
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        panel.add(console.getComponent(), BorderLayout.CENTER);

2、    final Content content = layoutUi.createContent("ConsoleContent", panel, "executable sql statements", AllIcons.Debugger.Console, panel);
        content.setCloseable(true);
        layoutUi.addContent(content);
3、控制台打印文本:console.print("hello", ConsoleViewContentType.USER_INPUT);

  

五、RunnerLayoutUi添加按钮事件

1、创建按钮组
final DefaultActionGroup actionGroup = new DefaultActionGroup();
        actionGroup.add(new anaction()));

2、ui添加按钮
layoutUi.getOptions().setLeftToolbar(actionGroup, "RunnerToolbar");

  

六、控制台过滤器:ConsoleFilterProvider,Filter

1、实现Filter
public class MyFilter implements Filter {

    @Nullable
    @Override
    public Result applyFilter(@NotNull String s, int i) {
        System.out.println("sss=>" + s);
        System.out.println("i=" + i);
        return null;
    }
}

2、实现ConsoleFilterProvider,配置过滤器
public class MyConsoleFilterProvider implements ConsoleFilterProvider {

    @NotNull
    @Override
    public Filter[] getDefaultFilters(@NotNull Project project) {
        MyFilter filter = new MyFilter();
        return new Filter[]{filter};
    }
}

3、plugin.xml配置ConsoleFilterProvider
  <extensions defaultExtensionNs="com.intellij">
    <consoleFilterProvider implementation="com.log.provider.MyConsoleFilterProvider"/>
  </extensions>

  

七、创建选项:ListPopup

1、 plugin.xml配置事件组
<actions>
    <group id="Test-Group-id" text="Test-Group" >
    </group>
  </actions>
2、创建一个事件AnAction触发选项ListPopup
public class ProPlug extends AnAction {
    @Override
    public void actionPerformed(@NotNull AnActionEvent e) {
// 获取plugin.xml配置的事件组
        DefaultActionGroup group = (DefaultActionGroup) ActionManager.getInstance().getAction("Test-Group-id");
// 清空所有事件
        group.removeAll();
// 添加一个事件AnAction
        group.add(new AnAction("New-Anaction") {
            @Override
            public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
                System.out.println("this is new Anaction.....");
            }
        });
// 获取工程的选项对象ListPoup
        ListPopup myPopup = JBPopupFactory.getInstance().createActionGroupPopup("MyPopup", group, e.getDataContext(),
                JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, false);
// ListPopub的显示位置,showCenteredInCurrentWindow当前窗口中间弹出,showInCenterOf在一个组件中间弹出
        myPopup.showInBestPositionFor(e.getDataContext());
    }
}

  

八、显示提示框 

        Editor editor = e.getData(CommonDataKeys.EDITOR);
        ApplicationManager.getApplication().invokeLater(() -> {
            JBPopupFactory factory = JBPopupFactory.getInstance();
            factory.createHtmlTextBalloonBuilder("hello", null,
                    new JBColor(new Color(186, 238, 186), new Color(73, 117, 73)), null)
                    .setFadeoutTime(5000L)
                    .createBalloon()
                    .show(factory.guessBestPopupLocation(editor), Balloon.Position.above);
        });

  

九、复制文本到剪贴板

        CopyPasteManager.getInstance().setContents(new StringSelection("this is copy content"));

十、创建toolWindow工具

1、右键新建GUI Form:MyForm继承SimpleToolWindowPanel
2、初始化构造器,添加根面板到MyForm
3、自定义布局form界面
4、客户端获取JPanel
5、创建ToolWindow工具并注册JPanel

public class MyForm extends SimpleToolWindowPanel {
    private JPanel parentPanel;
    private JTabbedPane tabbedPane1;
    private SimpleTree tree1;
    private JTextField textField1;
    private JTextField textField2;
    private JButton button1;
    private JTextArea textArea1;

    public MyForm(Project project) {
        super(true, true);
         // 初始化构造器,添加根面板到MyForm
        add(parentPanel);
    }
}
public void actionPerformed(AnActionEvent e) {
    // 客户端获取JPanel
    // JPanel jPanel = new OtherForm(e.getProject());
        JPanel jPanel = e.getProject().getComponent(MyForm.class);
        ContentFactory factory = ServiceManager.getService(ContentFactory.class);
        Content content = factory.createContent(jPanel, "New Panel", false);
        ToolWindowManager manager = ToolWindowManager.getInstance(e.getProject());
        ToolWindow toolWindow = manager.registerToolWindow("NewTest", false, ToolWindowAnchor.RIGHT);
        ContentManager contentManager = toolWindow.getContentManager();
        contentManager.addContent(content);
        contentManager.setSelectedContent(content, false);
}

十一、弹出消息框

            Messages.showMessageDialog("hello", "New-Message", Messages.getInformationIcon());

  

十二、按钮添加事件

JButton.addActionListener((e)->{ Messages.showMessageDialog("hello", "New-Message", Messages.getInformationIcon()); });

  

十二、动态添加menu

       ActionManager actionManager = ActionManager.getInstance();
            DefaultActionGroup codeMenu = (DefaultActionGroup) actionManager.getAction("EditMenu");
            codeMenu.add(new AnAction("New-Action") {
                @Override
                public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
                    Messages.showMessageDialog("hello", "New-Message", Messages.getInformationIcon());
                }
            });

  

十三、导航跳转

NavigationItem.navigate(true)

  

十四、JTree树配置

1、创建MyNavigationItem实现NavigationItem,保存PsiElement和NavigationItem
public class MyNavigationItem implements NavigationItem {
    private PsiElement psielment;
    private NavigationItem navigationItem;
    private String name;
    public MyNavigationItem(PsiElement psiElement) {
        this.psielment = psiElement;
        if (psiElement instanceof PsiMethod) {
            PsiMethod method = (PsiMethod) psiElement;
            this.name = method.getName();
        }
        if (psiElement instanceof NavigationItem) {
            this.navigationItem = (NavigationItem) psiElement;
        }

    }

    @Nullable
    @Override
    public String getName() {
        return name;
    }

    @Nullable
    @Override
    public ItemPresentation getPresentation() {
        return new MyItemPresentation(name);
    }

    @Override
    public void navigate(boolean b) {
        if (null != navigationItem) {
            navigationItem.navigate(b);
        }
    }

    @Override
    public boolean canNavigate() {
        return true;
    }

    @Override
    public boolean canNavigateToSource() {
        return true;
    }
}



2、创建树节点MyTreeNode继承CachingSimpleNode
	public class MyTreeNode extends CachingSimpleNode {

	private SimpleNode parent;
	private MyNavigationItem myNavigationItem;
	private List<MyTreeNode> children = new ArrayList<>();
	private String name;

	protected MyTreeNode(String name, SimpleNode parent, PsiElement psiElement) {
		super(parent);
		this.getTemplatePresentation().setIcon(Module);
		this.setIcon(Module);
		this.parent = parent;
		if (null != psiElement) {
			this.myNavigationItem = new MyNavigationItem(psiElement);
		}
		this.name = name;
	}

	@Override
	protected SimpleNode[] buildChildren() {
		return children.parallelStream().toArray(SimpleNode[]::new);
	}

	public List<MyTreeNode> children() {
		return children;
	}

	@Override
	public String getName() {
		return name;
	}

// 双击树节点

	@Override
	public void handleDoubleClickOrEnter(SimpleTree tree, InputEvent inputEvent) {
		SimpleNode selectedNode = tree.getSelectedNode();
			if (selectedNode instanceof MyTreeNode) {
			MyTreeNode myTreeNode = (MyTreeNode) selectedNode;
				if (null != myTreeNode.myNavigationItem) {
					myNavigationItem.navigate(true);
				}
			}
		}
	}

3、创建MySimpleTreeStrure继承SimpleTreeStructure,重写getRootElement
public class MySimpleTreeStructure extends SimpleTreeStructure {

    private MyTreeNode root;

    public MySimpleTreeStructure(Project project) {
        root = new MyTreeNode(project.getName(), null, null);
        Module[] modules = ModuleManager.getInstance(project).getModules();
        if (modules != null && modules.length > 0) {
            List<MyTreeNode> children = root.children();
            for (Module module : modules) {
                MyTreeNode moduleNode = new MyTreeNode(module.getName(), root, null);
                List<MyTreeNode> moduleChild = moduleNode.children();
                children.add(moduleNode);

                Collection<PsiAnnotation> controller = JavaAnnotationIndex.getInstance().get("Controller", project, GlobalSearchScope.moduleScope(module));

                if (null != controller && controller.size() > 0) {

                    for (PsiAnnotation psiAnnotation : controller) {
                        PsiClass psiClass = (PsiClass) psiAnnotation.getParent().getParent();
                        PsiMethod[] methods = psiClass.getMethods();
                        if (null != methods && methods.length > 0) {
                            for (PsiMethod method : methods) {
                                moduleChild.add(new MyTreeNode(method.getName(), moduleNode, method));
                            }
                        }
                    }

                }
            }
        }
    }

    @NotNull
    @Override
    public Object getRootElement() {
        return root;
    }

    public SimpleNode getRoot() {
        return root;
    }
}



4、初始化SimpleTreeBuilder
 MySimpleTreeStructure structure = new MySimpleTreeStructure(project);
        SimpleTreeBuilder myTreeBuilder = new SimpleTreeBuilder(tree1, (DefaultTreeModel)tree1.getModel(), structure, null);
        Disposer.register(project, myTreeBuilder);
        myTreeBuilder.initRoot();
        myTreeBuilder.expand(structure.getRoot(), null);

  

十五、搜索框

1、新建入口AnAction继承GotoActionBase

public class NewGotoActionBase extends GotoActionBase {

    @Override
    protected void gotoActionPerformed(@NotNull AnActionEvent e) {
        MyChooseByname chooseByname = new MyChooseByname();
        ChooseByNameContributor[] butor = new ChooseByNameContributor[]{chooseByname};
        FilterModel model = new FilterModel(e.getProject(), butor);
        GotoActionCallback callback = new GotoActionCallback() {
            @Override
            public void elementChosen(ChooseByNamePopup chooseByNamePopup, Object o) {
                Messages.showInfoMessage("Hello", "Title");
            }
        };
        showNavigationPopup(e, model, callback);
    }
}



2、创建数据提供者MyChooseByName实现ChooseByNameContributor
public class MyChooseByname implements ChooseByNameContributor {
    List<MyNavigationItem> list = new ArrayList<>();

    public MyChooseByname() {
        for (int i = 0; i < 20; i++) {
            list.add(new MyNavigationItem(i + "", null));
        }
    }

    /**
     * @description: 提供全部选项
     *
     * @author: chenzhiwei
     * @create: 2020/5/16 22:31
     * @return java.lang.String[] 
     */
    @NotNull
    @Override
    public String[] getNames(Project project, boolean b) {
        return list.parallelStream().map(MyNavigationItem::getValue).toArray(String[]::new);
    }

    /**
     * @description: 匹配到符合的项
     *
     * @author: chenzhiwei
     * @create: 2020/5/16 22:31
     * @return com.intellij.navigation.NavigationItem[] 
     */
    @NotNull
    @Override
    public NavigationItem[] getItemsByName(String s, String s1, Project project, boolean b) {
        NavigationItem[] navigationItems = list.parallelStream().filter(
                p -> p.getValue().equals(s)
        )
                .toArray(NavigationItem[]::new);
        System.out.println("array="+ Arrays.toString(navigationItems));
        return navigationItems;
    }
}



3、创建搜索框模型MyFliteringGotoByModel继承FilteringGotoByModel
public class FilterModel extends FilteringGotoByModel {

    protected FilterModel(@NotNull Project project, @NotNull ChooseByNameContributor[] contributors) {
        super(project, contributors);
    }

    /**
     * @description: 命中选项
     *
     * @author: chenzhiwei
     * @create: 2020/5/16 22:32
     * @return java.lang.Object
     */
    @Nullable
    @Override
    protected Object filterValueFor(NavigationItem navigationItem) {
        if (navigationItem instanceof MyNavigationItem) {
            MyNavigationItem myNavigationItem = (MyNavigationItem) navigationItem;
            return myNavigationItem.getValue();
        }
        return null;
    }

    /**
     * @description: 搜索框标题
     *
     * @author: chenzhiwei
     * @create: 2020/5/16 22:32
     * @return java.lang.String
     */
    @Nls(capitalization = Nls.Capitalization.Sentence)
    @Override
    public String getPromptText() {
        return "Enter";
    }

    @NotNull
    @Override
    public String getNotInMessage() {
        return "Not in Message";
    }

    @NotNull
    @Override
    public String getNotFoundMessage() {
        return "Not Found message";
    }

    /**
     * @description: 过滤器是否打开
     *
     * @author: chenzhiwei
     * @create: 2020/5/16 22:33
     * @return java.lang.String
     */
    @Nullable
    @Override
    public String getCheckBoxName() {
        return "New Check";
    }

    @Override
    public boolean loadInitialCheckBoxState() {
        return false;
    }

    @Override
    public void saveInitialCheckBoxState(boolean b) {
    }

    @NotNull
    @Override
    public String[] getSeparators() {
        return new String[]{"/","?"};
    }

    /**
     * @description: 必须重写,返回数据项
     *
     * @author: chenzhiwei
     * @create: 2020/5/16 22:33
     * @return java.lang.String
     */
    @Nullable
    @Override
    public String getFullName(@NotNull Object element) {
        return ((MyNavigationItem)element).getValue();
    }

    @Override
    public boolean willOpenEditor() {
        return true;
    }

}



4、在GotoActionBase中创建回调函数GotoActionCallback
     // 初始化回调函数
        GotoActionCallback callback = new GotoActionCallback() {
            @Override
            public void elementChosen(ChooseByNamePopup chooseByNamePopup, Object o) {
                Messages.showInfoMessage("Hello", "Title");
            }
        };



6、弹出搜索框showNavigationPopup(e,model,callback)

7、添加过滤器,新建过滤器指定类型FilterDemo
public class FilterDemo {
    private String name;
    private String value;

    public FilterDemo(String name, String value) {
        this.name = name;
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}



8、在MyNavigationItem中维护FilterDemo
public class MyNavigationItem implements NavigationItem {
    private PsiElement psielment;
    private NavigationItem navigationItem;
    private String name;
    private FilterDemo demo;

    public MyNavigationItem(String name, PsiElement psiElement) {
        this.psielment = psiElement;
        if (psiElement instanceof PsiMethod) {
            PsiMethod method = (PsiMethod) psiElement;
            this.name = method.getName();
        }
        if (psiElement instanceof NavigationItem) {
            this.navigationItem = (NavigationItem) psiElement;
        }
        this.name = name;
        demo = new FilterDemo(name, name);
    }

    @Nullable
    @Override
    public String getName() {
        return name;
    }

    @Nullable
    @Override
    public ItemPresentation getPresentation() {
        return new MyItemPresentation(name);
    }

    @Override
    public void navigate(boolean b) {
        if (null != navigationItem) {
            navigationItem.navigate(b);
        }
    }

    @Override
    public boolean canNavigate() {
        return true;
    }

    @Override
    public boolean canNavigateToSource() {
        return true;
    }

    public String getValue() {
        return this.name;
    }

    public FilterDemo getDemo() {
        return demo;
    }


9、在MyFilteringGotoByModel添加泛型FilterDemo,如FilteringGotoByModel<FilterDemo>
public class FilterModel extends FilteringGotoByModel<FilterDemo> {

    protected FilterModel(@NotNull Project project, @NotNull ChooseByNameContributor[] contributors) {
        super(project, contributors);
    }

    /**
     * @description: 命中选项
     *
     * @author: chenzhiwei
     * @create: 2020/5/16 22:32
     * @return java.lang.Object
     */
    @Nullable
    @Override
    protected FilterDemo filterValueFor(NavigationItem navigationItem) {
        if (navigationItem instanceof MyNavigationItem) {
            MyNavigationItem myNavigationItem = (MyNavigationItem) navigationItem;
            return myNavigationItem.getDemo();
        }
        return null;
    }

    /**
     * @description: 搜索框标题
     *
     * @author: chenzhiwei
     * @create: 2020/5/16 22:32
     * @return java.lang.String
     */
    @Nls(capitalization = Nls.Capitalization.Sentence)
    @Override
    public String getPromptText() {
        return "Enter";
    }

    @NotNull
    @Override
    public String getNotInMessage() {
        return "Not in Message";
    }

    @NotNull
    @Override
    public String getNotFoundMessage() {
        return "Not Found message";
    }

    /**
     * @description: 过滤器是否打开
     *
     * @author: chenzhiwei
     * @create: 2020/5/16 22:33
     * @return java.lang.String
     */
    @Nullable
    @Override
    public String getCheckBoxName() {
        return "New Check";
    }

    @Override
    public boolean loadInitialCheckBoxState() {
        return false;
    }

    @Override
    public void saveInitialCheckBoxState(boolean b) {
    }

    @NotNull
    @Override
    public String[] getSeparators() {
        return new String[]{"/","?"};
    }

    /**
     * @description: 必须重写,返回数据项
     *
     * @author: chenzhiwei
     * @create: 2020/5/16 22:33
     * @return java.lang.String
     */
    @Nullable
    @Override
    public String getFullName(@NotNull Object element) {
        return ((MyNavigationItem)element).getValue();
    }

    @Override
    public boolean willOpenEditor() {
        return true;
    }

}



10、新建MyChooseByNameFilter过滤器继承ChooseByNameFilter<FilterDemo>
public class MyChooseByNameFilter extends ChooseByNameFilter<FilterDemo> {

    public MyChooseByNameFilter(@NotNull ChooseByNamePopup popup, @NotNull FilteringGotoByModel<FilterDemo> model, @NotNull Project project) {
        super(popup, model, new MyChooseByNameFilterConfiguration(), project);
    }

    @Override
    protected String textForFilterValue(@NotNull FilterDemo filterDemo) {
        return filterDemo.getValue();
    }

    @Nullable
    @Override
    protected Icon iconForFilterValue(@NotNull FilterDemo filterDemo) {
        return null;
    }

    @NotNull
    @Override
    protected Collection<FilterDemo> getAllFilterValues() {

        List<MyNavigationItem> list = MyChooseByname.list;
        List<FilterDemo> collect = list.parallelStream().map(MyNavigationItem::getDemo)
                .collect(Collectors.toList());
        return collect;
    }
}



10、新建MyChooseByNameFilterCondiguration继承ChooseByNameFilterConfiguration<FilterDemo>,并交给plugin.xml维护
public class MyChooseByNameFilterConfiguration extends ChooseByNameFilterConfiguration<FilterDemo> {


    @Override
    protected String nameForElement(FilterDemo filterDemo) {
        return filterDemo.getValue();
    }
}

  <extensions defaultExtensionNs="com.intellij">
    <projectService serviceImplementation="MyChooseByNameFilterConfiguration"/>
  </extensions>

11、在callback中实现createFilter方法,返回实例化的MyChooseByNameFilter对象
public class NewGotoActionBase extends GotoActionBase {

    @Override
    protected void gotoActionPerformed(@NotNull AnActionEvent e) {
        MyChooseByname chooseByname = new MyChooseByname();
        ChooseByNameContributor[] butor = new ChooseByNameContributor[]{chooseByname};
        FilterModel model = new FilterModel(e.getProject(), butor);
        // 初始化回调函数
        GotoActionCallback callback = new GotoActionCallback() {
            @Nullable
            @Override
            protected ChooseByNameFilter createFilter(@NotNull ChooseByNamePopup popup) {
                return new MyChooseByNameFilter(popup, model, e.getProject());
            }

            @Override
            public void elementChosen(ChooseByNamePopup chooseByNamePopup, Object o) {
                Messages.showInfoMessage("Hello", "Title");
            }
        };
        showNavigationPopup(e, model, callback);
    }
}


 12、注意:FilterDemo必须是同一个对象

13、搜索框搜索的时候显示辅助内容,新建MyItemPresentation
public class MyItemPresentation implements ItemPresentation {
    private String name;
    public MyItemPresentation(String name) {
        this.name = name;
    }

    /**
     * @description: 搜索结果最终显示
     *
     * @author: chenzhiwei
     * @create: 2020/5/17 10:16
     * @return java.lang.String 
     */
    @Nullable
    @Override
    public String getPresentableText() {
        return name;
    }

    /**
     * @description: 搜索结果的辅助说明
     *
     * @author: chenzhiwei
     * @create: 2020/5/17 10:16
     * @return java.lang.String 
     */
    @Nullable
    @Override
    public String getLocationString() {
        return "getLocationString";
    }

    /**
     * @description: 搜索结果的图标
     *
     * @author: chenzhiwei
     * @create: 2020/5/17 10:16
     * @return javax.swing.Icon 
     */
    @Nullable
    @Override
    public Icon getIcon(boolean b) {
        return null;
    }
}

十六、树节点鼠标右键菜单Popup

public class NewForm extends SimpleToolWindowPanel {

    private JPanel parentPanel;
    private JTree tree1;

    public NewForm(Project project) {
        super(true, true);
        add(parentPanel);

        MyTreeStructure structure = new MyTreeStructure(project);
        SimpleTreeBuilder builder = new SimpleTreeBuilder(tree1, (DefaultTreeModel) tree1.getModel(), structure, null);
        Disposer.register(project, builder);
        builder.initRoot();
        builder.expand(structure.getRootElement(), null);

        tree1.addMouseListener(new PopupHandler() {
            @Override
            public void invokePopup(Component component, int x, int y) {
                ActionManager manager = ActionManager.getInstance();
                ActionGroup actionGroup = (ActionGroup) manager.getAction("popupMenu");
                JPopupMenu newMyPopup = manager.createActionPopupMenu("NewMyPopup", actionGroup).getComponent();
                newMyPopup.show(component, x, y);
            }
        });
    }
}

plugin.xml配置
  <actions>
    <group id="popupMenu" text="PopupMenus" popup="true">
      <action class="NewPlugin" id="New One" text="New One" icon="AllIcons.Actions.Search"/>
      <action class="NewPlugin" id="New Two" text="New Two" icon="AllIcons.Actions.Refresh"/>
    </group>
  </actions>

十七、创建toolWindow工具方式二

1、创建SimpleToolWindowPanel(JPanel)并布局:如MyForm
public class MyForm extends SimpleToolWindowPanel {
    private JPanel parentPanel;
    private JTabbedPane tabbedPane1;
    private SimpleTree tree1;
    private JTextField textField1;
    private JTextField textField2;
    private JButton button1;
    private JTextArea textArea1;

    public MyForm(Project project) {
        super(true, true);
        MySimpleTreeStructure structure = new MySimpleTreeStructure(project);
        SimpleTreeBuilder myTreeBuilder = new SimpleTreeBuilder(tree1, (DefaultTreeModel)tree1.getModel(), structure, null);
        Disposer.register(project, myTreeBuilder);
        myTreeBuilder.initRoot();
        myTreeBuilder.expand(structure.getRoot(), null);



        add(parentPanel);
        button1.addActionListener((e)->{
            ActionManager actionManager = ActionManager.getInstance();
            DefaultActionGroup codeMenu = (DefaultActionGroup) actionManager.getAction("EditMenu");
            codeMenu.add(new AnAction("New-Action") {
                @Override
                public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
                    Messages.showMessageDialog("hello", "New-Message", Messages.getInformationIcon());
                }
            });
        });
    }
}

2、创建tool window的工厂:ToolWindowFactory
public class ToolFactory implements ToolWindowFactory {

    @Override
    public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
        Content content = toolWindow.getContentManager().getFactory().createContent(project.getComponent(MyForm.class), "New-Panel", false);
        toolWindow.getContentManager().addContent(content);
        toolWindow.setTitle("New Tool");
        toolWindow.setType(ToolWindowType.DOCKED, null);
    }
}

3、在配置pugin.xml中配置tool window
 <extensions defaultExtensionNs="com.intellij">
    <toolWindow anchor="bottom" id="NewTool" factoryClass="ToolFactory"/>
  </extensions>

4、获取tool window
ToolWindow toolWindow = ToolWindowManager.getInstance(e.getProject()).getToolWindow("NewTool");
        toolWindow.activate(()->{
            System.out.println("show");
        });

  

 十八、JTree配置方式二:待定

十九:ToolWindowBar:Panel添加toolBar

public class NewForm extends SimpleToolWindowPanel {

    private JPanel parentPanel;
    private JTree tree1;

    public NewForm(Project project) {
        super(true, true);
        add(parentPanel);
        ActionGroup popupMenu = (ActionGroup) ActionManager.getInstance().getAction("popupMenu");
        ActionToolbar newToolBar = ActionManager.getInstance().createActionToolbar("New Tool Bar", popupMenu, false);
        setToolbar(newToolBar.getComponent());

    }
}


plugin.xml配置
  <actions>
    <group id="popupMenu" text="PopupMenus" popup="true">
      <action class="NewPlugin" id="New One" text="New One" icon="AllIcons.Actions.Search"/>
      <action class="NewPlugin" id="New Two" text="New Two" icon="AllIcons.Actions.Refresh"/>
    </group>
  </actions>

二十:获得当前编辑器

new AnAction("AddAction","Nothing", AllIcons.Actions.Back) {
            @Override
            public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
                Editor editor = anActionEvent.getData(CommonDataKeys.EDITOR);
                WriteCommandAction.runWriteCommandAction(anActionEvent.getProject(),()->{
                    // 插入的位置:当前光标的位置
            int position = editor.getCaretModel().getOffset(); editor.getDocument().insertString(position,
"Hello"); }); } });


二十一:定位到行列

new AnAction("AddAction","Nothing", AllIcons.Actions.Back) {
            @Override
            public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
                Editor editor = anActionEvent.getData(CommonDataKeys.EDITOR);
                // 行数,从0开始
                int line = 11;
                // 列数,从1开始
                int column = 12;
                LogicalPosition position = new LogicalPosition(line, column);
                editor.getCaretModel().moveToLogicalPosition(position);
                editor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
            }
        }

 二十二、添加控制台方式二

1、创建console组件:    
    ConsoleView console = TextConsoleBuilderFactory.getInstance().createBuilder(project).getConsole();
2、初始化console到SimpleToolWindowPanel面板:
 jpanel.setLayout(new BorderLayout());
        jpanel.add(console.getComponent(), "Center");
3、在控制台打印数据:
        console.print("hello world", ConsoleViewContentType.NORMAL_OUTPUT);

注意:console先在panel中初始化,再初l始化toolWindowBar组件
将console放在JPanel中,则需要设置边框laout和位置Center

  

二十三、新建窗口弹窗

1、右键新建Frame继承JFrame

2、构造函数添加顶层组件 add(parentPanel)

3、实例化JFrame 

public class NewFrame extends JFrame {
    private JTextField textField1;
    private JTextField textField2;
    private JPanel rootPanel;

    public NewFrame() {
        add(rootPanel);
    }
}

public class MyPlugin extends AnAction {

    @Override
    public void actionPerformed(AnActionEvent e) {
        NewFrame frame = new NewFrame();
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setSize(500, 300);
        frame.setVisible(true);

    }
}

二十四、新建对话框弹框JDialog

右键新建Dialog并进行布局
@Override
    public void actionPerformed(AnActionEvent e) {
        MyDialog dialog = new MyDialog();
        dialog.pack();
        dialog.setSize(500, 300);
        dialog.setVisible(true);
        System.exit(0);
    }

   

二十五、图标跳转

1、新建MyLineMarkerProvider实现LineMarkerProvider重写collectSlowLineMarkers方法

public class MyLineMarkerProvider implements LineMarkerProvider {

    @Nullable
    @Override
    public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement psiElement) {
        return null;
    }

    @Override
    public void collectSlowLineMarkers(@NotNull List<PsiElement> elements, @NotNull Collection<LineMarkerInfo> result) {
        for (PsiElement element : elements) {
            if (element instanceof PsiMethod) {
                NavigationGutterIconBuilder<PsiElement> builder = NavigationGutterIconBuilder
                        // 图标显示
                        .create(AllIcons.Actions.Scratch)
                        .setAlignment(GutterIconRenderer.Alignment.CENTER)
                        // 跳转目标
                        .setTarget(element)
                        .setTooltipTitle("");
                // 跳转源头
                result.add(builder.createLineMarkerInfo(element));
            }
        }
    }
}

plugin.xml配置
<extensions defaultExtensionNs="com.intellij"> <codeInsight.lineMarkerProvider language="JAVA" implementationClass="MyLineMarkerProvider"/> </extensions>

 二十六、右键new创建文件

1、新建事件继承CreateElementActionBase,重写invokeDialog,create

public class MyCreateElementActionBase extends CreateElementActionBase {
    public MyCreateElementActionBase() {
        // 菜单显示名称,描述,图标
        super("MyCreateElementActionBaseShow", "Create new XML File", AllIcons.Actions.Refresh);
    }

    @NotNull
    @Override
    protected PsiElement[] invokeDialog(Project project, PsiDirectory directory) {
        MyInputValidator validator = new MyInputValidator( project, directory);
        Messages.showInputDialog(project, "输入", "New", AllIcons.Actions.Scratch, "", validator);
        return validator.getCreatedElements();
    }

    @NotNull
    @Override
    protected PsiElement[] create(@NotNull String s, PsiDirectory psiDirectory) throws Exception {
        String text = "<idea-plugin>\n" +
                "</idea-plugin>";
        // 创建文件
        PsiFile f = PsiFileFactory.getInstance(psiDirectory.getProject()).createFileFromText(s + ".xml", new MyFileTypeIdentifiableByVirtualFile(), text);
        // 添加到当前文件夹
        psiDirectory.add(f);
        PsiElement lastChild = f.getLastChild();

        return new PsiElement[]{lastChild, f};
    }

    @Nls(capitalization = Nls.Capitalization.Title)
    @Override
    protected String getErrorTitle() {
        return "出现异常";
    }

    @Nls
    @Override
    protected String getActionName(PsiDirectory psiDirectory, String s) {
        return null;
    }

}


2、添加到new菜单NewGroup
<actions>
    <action id="  MyCreateElementActionBase " class="MyCreateElementActionBase" text="MyCreateElementActionBase" description="MyCreateElementActionBase">
      <add-to-group group-id="NewGroup" anchor="last"/>
    </action>
  </actions>


3|设置文件类型:FileTypeIdentifiableByVirtualFile
public class MyFileTypeIdentifiableByVirtualFile implements FileTypeIdentifiableByVirtualFile {
    @Override
    public boolean isMyFileType(@NotNull VirtualFile virtualFile) {
        return false;
    }

    @NotNull
    @Override
    public String getName() {
        return "xml";
    }

    @Nls(capitalization = Nls.Capitalization.Sentence)
    @NotNull
    @Override
    public String getDescription() {
        return "xml";
    }

    @NotNull
    @Override
    public String getDefaultExtension() {
        return "xml";
    }

    @Nullable
    @Override
    public Icon getIcon() {
        return AllIcons.Actions.Scratch;
    }

    @Override
    public boolean isBinary() {
        return false;
    }

    @Override
    public boolean isReadOnly() {
        return false;
    }

    @Nullable
    @Override
    public String getCharset(@NotNull VirtualFile virtualFile, @NotNull byte[] bytes) {
        return null;
    }
}

二十七:弹出输入框

 String input = Messages.showInputDialog(e.getProject(), "Input", "New", AllIcons.Actions.Scratch, "", null);
        Messages.showInfoMessage(input, "New Title");

 二十八,控制台日志着色

1、创建MyFilter实现Filter
public class MyFilter implements Filter {
    private static Integer offset = 0;

    @Nullable
    @Override
    public Result applyFilter(@NotNull String s, int i) {
        offset += s.length();
        Result result = null;
        if (s.length() > 5) {
            TextAttributes textAttributes = new TextAttributes();
            textAttributes.setBackgroundColor(JBColor.WHITE);
            textAttributes.setForegroundColor(JBColor.RED);

            TextAttributes textAttributes2 = new TextAttributes();
            textAttributes2.setBackgroundColor(JBColor.YELLOW);
            textAttributes2.setForegroundColor(JBColor.GREEN);

            // 点击日志跳转
            HyperlinkInfo info = new HyperlinkInfo() {
                @Override
                public void navigate(Project project) {
                    navigate(project);
                }
            };
            
            List<ResultItem> list = new ArrayList<>();
            // 前段白底红字
            ResultItem item = new ResultItem(offset - s.length(), offset - 5, info, textAttributes);
            // 最后5个字符黄底绿字
            ResultItem item2 = new ResultItem(offset - 5, offset, info, textAttributes2);
            list.add(item);
            list.add(item2);
            result = new Result(list);
        }

        return result;
    }
}

2、新建MyConsoleFilterProvider实现ConsoleFilterProvider
public class MyConsoleFilterProvider implements ConsoleFilterProvider {

    @NotNull
    @Override
    public Filter[] getDefaultFilters(@NotNull Project project) {
        return new Filter[]{new MyFilter()};
    }
}

3、plugin.xml
  <extensions defaultExtensionNs="com.intellij">
    <consoleFilterProvider implementation="MyConsoleFilterProvider" />
  </extensions>

二十六:日志折叠

1、新建MyConsoleFolding实现接口ConsoleFolding
public class MyConsoleFolding extends ConsoleFolding {

    @Override
    public boolean shouldFoldLine(@NotNull Project project, @NotNull String line) {
        // 如果包含hello字符则折叠
        return line.contains("hello");
    }

    @Nullable
    @Override
    public String getPlaceholderText(@NotNull Project project, @NotNull List<String> lines) {
        return "< line" + lines.size() + ">";
    }
}

2、plugin.xml配置
  <extensions defaultExtensionNs="com.intellij">
    <console.folding implementation="MyConsoleFolding"/>
  </extensions>

二十七:全局设置页添加面板

1、新建MyConfigurable实现接口Configurable
public class MyConfigurable implements Configurable {

    @Nls(capitalization = Nls.Capitalization.Title)
    @Override
    public String getDisplayName() {
        return "设置面板";
    }

    @Nullable
    @Override
    public JComponent createComponent() {
        return new ConfigFrame();
    }

    @Override
    public boolean isModified() {
        return false;
    }

    @Override
    public void apply() throws ConfigurationException {

    }
}

2、plugin.xml配置
  <extensions defaultExtensionNs="com.intellij">
    <applicationConfigurable id="myConfigurable" displayName="新面板" implementation="MyConfigurable"/>
  </extensions>

3、添加panel
public class ConfigFrame extends SimpleToolWindowPanel {
    private JTree tree1;
    private JPanel rootPanel;

    public ConfigFrame() {
        super(true, true);
        add(rootPanel);
    }
}

 二十八:日志输入过滤器实现接口ConsoleInputFilterProvider

plugin.xml配置consolInputFilterProvider

二十九:JEditorPanel组件添加超链接 

1、将JEditorPane设置为不可编辑
        editorPane1.setEditable(false);

2、将JEditorPane设置为网页格式
        editorPane1.setContentType("text/html");

3、JEditorPane中添加a标签
        editorPane1.setText("<a href=\"http://www.baidu.com\">百度</a>");

4、添加超链接监听器HyperlinkListener
        editorPane1.addHyperlinkListener(e -> {
            if (Desktop.isDesktopSupported() && e.getEventType() != HyperlinkEvent.EventType.ACTIVATED) {
                try {
                    Desktop.getDesktop().browse(e.getURL().toURI());
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                } catch (URISyntaxException uriSyntaxException) {
                    uriSyntaxException.printStackTrace();
                }
            }
        });


三十:插件更新提示

public class MyPlugin extends AnAction {

    @Override
    public void actionPerformed(AnActionEvent e) {
        NotificationGroup group = new NotificationGroup("MyNotifyId", NotificationDisplayType.BALLOON, true);
        Notification notification = group.createNotification("MyTitle", "省略...", "内容", NotificationType.INFORMATION);
        NotificationAction actions = new NotificationAction("点击按钮") {
            @Override
            public void actionPerformed(@NotNull AnActionEvent anActionEvent, @NotNull Notification notification) {
                Messages.showInfoMessage("提示内容", "提示标题");
            }
        };
        notification.addAction(actions);
        notification.notify(e.getProject());

    }


三十一:配置数据持久化:@State,
PersistentStateComponent
1、新建配置类,用来持久化数据StorageConfig
public class StorageConfig {
    private String name;
    private String value;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

2、新建数据持久化state类MyState
@State(name = "MyStorage",storages = {@Storage("my-config.xml")})
public class MyState implements PersistentStateComponent<MyState> {

    private StorageConfig config;

    public static MyState getInstance(){
        return ServiceManager.getService(MyState.class);
    }

    @Nullable
    @Override
    public MyState getState() {
        return this;
    }

    @Override
    public void loadState(@NotNull MyState myState) {
        if (null == myState) {
            return;
        }
        XmlSerializerUtil.copyBean(myState, this);
    }

    public StorageConfig getConfig() {
        if (null == config) {
            config = new StorageConfig();
        }
        return config;
    }

    public void setConfig(StorageConfig config) {
        this.config = config;
    }
}


3、新建面板JFrame:ConfigFrame
public class ConfigFrame extends SimpleToolWindowPanel {
    private JTree tree1;
    private JPanel rootPanel;
    private JTextField textField1;
    private JButton button1;

    public ConfigFrame() {
        super(true, true);
        add(rootPanel);
        button1.addActionListener(e -> apply());
    }

    public void apply() {
        StorageConfig config = MyState.getInstance().getConfig();
        if (null == config) {
            config = new StorageConfig();
        }
        config.setName(textField1.getText());
        config.setValue(textField1.getText() + "-new");
    }
}

4、新建设置面板类MyConfig
public class MyConfig implements SearchableConfigurable {

    private ConfigFrame frame;

    @NotNull
    @Override
    public String getId() {
        return "MyConfig";
    }

    @Nls(capitalization = Nls.Capitalization.Title)
    @Override
    public String getDisplayName() {
        return "设置面板";
    }

    @Nullable
    @Override
    public JComponent createComponent() {
        return frame = new ConfigFrame();
    }

    @Override
    public boolean isModified() {
        return false;
    }

    @Override
    public void apply() throws ConfigurationException {
        frame.apply();
    }
}

5、plugin.xml配置
  <extensions defaultExtensionNs="com.intellij">
    <applicationConfigurable id="MyConfig" displayName="新面板" implementation="MyConfig"/>
    <applicationService serviceImplementation="MyState"/>
  </extensions>

6、获取持久化配置的数据
 StorageConfig config = MyState.getInstance().getConfig();
        Messages.showInfoMessage(config.getName(), config.getValue()+"---");


三十一:在IDEA主窗口菜单栏添加菜单选项=>MainMenu

添加菜单组到IDEA主窗口菜单栏中:MainMenu
<actions>
    <group id="NewGroupId" text="MyMenu" popup="true">
      <add-to-group group-id="MainMenu" anchor="last"/>
      <action class="MyPlugin" text="MyPlugin" id="MyPluginss"/>
    </group>
  </actions>

三十二:新建项目继承NewProjectAction

public class MyCreateProjectAction extends NewProjectAction {
    
}

2、配置plugin.xml
 <group id="NewGroupId" text="MyMenu" popup="true">
      <action id="MyCreateProjectActionId" class="MyCreateProjectAction" text="MyCreateProjectAction"/>
      <add-to-group group-id="MainMenu" anchor="last"/>
    </group>


三十三:XML标签与java函数互相跳转

1、XML跳转java,plugin.xml的language="XML"
新建MyRelatedItemLineMarkerProvider 继承RelatedItemLineMarkerProvider实现collectNavigationMarkers
public class MyRelatedItemLineMarkerProvider extends RelatedItemLineMarkerProvider {

    private List<String> list = new ArrayList<>(Arrays.asList("select", "update", "insert", "delete"));

    @Override
    protected void collectNavigationMarkers(@NotNull PsiElement element, @NotNull Collection<? super RelatedItemLineMarkerInfo> result) {
        PsiFile containingFile = element.getContainingFile();
        if (containingFile instanceof XmlFile && element instanceof XmlTag) {
            XmlFile xmlFile = (com.intellij.psi.xml.XmlFile) containingFile;
            XmlTag rootTag = xmlFile.getRootTag();
            Project project = element.getProject();
            if ("mapper".equals(rootTag.getName())) {
                XmlAttribute namespace = rootTag.getAttribute("namespace");
                String substring = namespace.getValue().substring(namespace.getValue().lastIndexOf(".") + 1);
                XmlTag xmlTag = (XmlTag) element;
                if (StringUtils.isNotBlank(xmlTag.getName()) &&list.contains(xmlTag.getName())) {
                    XmlAttribute id = xmlTag.getAttribute("id");
                    if (StringUtils.isNotBlank(id.getValue())) {
                      // 查找文件
                        PsiFile psiFile = FilenameIndex.getFilesByName(project, substring + ".java", GlobalSearchScope.projectScope(project))[0];
                        PsiElement[] children = psiFile.getChildren();
                        List<PsiElement> collect = Stream.of(children).parallel()
                                .filter(p -> p instanceof PsiClass)
                                .collect(Collectors.toList());
                        if (CollectionUtils.isNotEmpty(collect)) {
                            PsiClass psiElement = (PsiClass) collect.get(0);
                            PsiMethod[] methods = psiElement.getMethods();
                            if (null != methods && methods.length > 0) {
                                for (PsiMethod method : methods) {
                                    if (method.getName().equals(id.getValue())) {
                                        NavigationGutterIconBuilder<PsiElement> builder = NavigationGutterIconBuilder
                                                .create(AllIcons.Actions.Back)
                                                .setTarget(method)
                                                .setTooltipTitle("go to method");
                                        result.add(builder.createLineMarkerInfo(element));
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }    
    }
}


plugin.xml配置
<extensions defaultExtensionNs="com.intellij">
    <codeInsight.lineMarkerProvider implementationClass="MyRelatedItemLineMarkerProvider" language="XML"/>
  </extensions>

2、java跳转xml,plugin.xml的language="JAVA"
新建MyRelatedItemLineMarkerProvider2继承RelatedItemLineMarkerProvider
public class MyRelatedItemLineMarkerProvider2 extends RelatedItemLineMarkerProvider {

    @Override
    protected void collectNavigationMarkers(@NotNull PsiElement element, @NotNull Collection<? super RelatedItemLineMarkerInfo> result) {

        if (element instanceof PsiMethod) {
            PsiMethod method = (PsiMethod) element;
            String packageName = ((PsiJavaFileImpl) method.getContainingFile()).getPackageName();
            PsiClass PsiClass = (PsiClass) method.getParent();
            String nameSpace = packageName + "." + PsiClass.getName();
            // PsiShortNamesCache.getInstance(element.getProject()).getAllFileNames() 获取所有文件名
            List<String> collect = Stream.of(PsiShortNamesCache.getInstance(element.getProject()).getAllFileNames())
                    .filter(p -> p.contains(".xml"))
                    .collect(Collectors.toList());
            // FilenameIndex.getFilesByName(element.getProject(), p, GlobalSearchScope.projectScope(element.getProject()))获取指定文件名的文件
            List<XmlFile> xmlFileList = collect.parallelStream().flatMap(p ->
                    Stream.of(FilenameIndex.getFilesByName(element.getProject(), p, GlobalSearchScope.projectScope(element.getProject()))))
                    .filter(p -> p instanceof XmlFile)
                    .map(p -> {
                        XmlFile file = (XmlFile) p;
                        return file;
                    })
                    .filter(p -> p.getRootTag().getAttribute("namespace") != null && p.getRootTag().getAttribute("namespace").getValue().equals(nameSpace))
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(xmlFileList)) {
                for (XmlFile xmlFile : xmlFileList) {
                    XmlTag rootTag = xmlFile.getRootTag();
                    XmlTag[] children = rootTag.getSubTags();
                    if (null != children && children.length > 0) {
                        List<XmlTag> id = Stream.of(children).parallel()
                                .filter(p -> p.getAttribute("id").getValue()!=null &&p.getAttribute("id").getValue().equals(method.getName()))
                                .collect(Collectors.toList());
                        if (CollectionUtils.isNotEmpty(id)) {
                            XmlTag xmlTag = id.get(0);
                            NavigationGutterIconBuilder<PsiElement> builder=NavigationGutterIconBuilder
                                    .create(AllIcons.Actions.Close)
                                    .setTarget(xmlTag)
                                    .setTooltipTitle("go to mapper");
                            result.add(builder.createLineMarkerInfo(element));
                        }
                    }
                }
            }
        }

    }

}

plugin.xml配置
<extensions defaultExtensionNs="com.intellij">
    <codeInsight.lineMarkerProvider implementationClass="MyRelatedItemLineMarkerProvider2" language="JAVA"/>
  </extensions>


三十四:新建项目自定义模板,核心类是ModuleBuilder
1、新建第一步的面板Frame:StepForm1 继承SimpleToolWindowPanel
public class StepForm1 extends SimpleToolWindowPanel {
    private JPanel panel;
    private JLabel label;

    public StepForm1() {
        super(true, true);
        add(panel);
        label.setText("第一步");
    }
}

2、新建第一步配置步骤,MyModuleWizardStep1继承ModuleWizardStep
public class MyModuleWizardStep1 extends ModuleWizardStep {

    @Override
    public JComponent getComponent() {
        return new StepForm1();
    }

    @Override
    public void updateDataModel() {

    }
}

3、新建第一二步面板:StepForm2继承SimpleToolWindowPanel
public class StepForm2 extends SimpleToolWindowPanel {
    private JPanel panel;
    private JLabel label;

    public StepForm2() {
        super(true, true);
        add(panel);
        label.setText("第二步");
    }
}

4、新建第二步配置步骤:MyModuleWizardStep2继承ModuleWizardStep
public class MyModuleWizardStep2 extends ModuleWizardStep {
    @Override
    public JComponent getComponent() {
        return new StepForm2();
    }

    @Override
    public void updateDataModel() {

    }
}


5、新建最后一步SDK配置步骤:MyModuleWizardStep3继承SdkSettingsStep
public class MyModuleWizardStep3 extends SdkSettingsStep {

    public MyModuleWizardStep3(SettingsStep settingsStep, @NotNull ModuleBuilder moduleBuilder, @NotNull Condition<? super SdkTypeId> sdkTypeIdFilter) {
        super(settingsStep, moduleBuilder, sdkTypeIdFilter);
    }
}

6、初始化新模块属性:MyModuleBuilder继承ModuleBuilder
public class MyModuleBuilder extends ModuleBuilder {

    /**
     * @description: 模块描述
     *
     * @author: chenzhiwei
     * @create: 2020/5/31 11:46
     * @return java.lang.String 
     */
    @Nls(capitalization = Nls.Capitalization.Sentence)
    @Override
    public String getDescription() {
        return "GetDescription";
    }

    /**
     * @description: 模块名称
     *
     * @author: chenzhiwei
     * @create: 2020/5/31 11:47
     * @return java.lang.String 
     */
    @Override
    public String getName() {
        return "newModule";
    }

    /**
     * @description: 模块名称显示
     *
     * @author: chenzhiwei
     * @create: 2020/5/31 11:47
     * @return java.lang.String 
     */
    @Nls(capitalization = Nls.Capitalization.Title)
    @Override
    public String getPresentableName() {
        return "新模块";
    }

    @Override
    public String getParentGroup() {
        return "JAVA";
    }

    @Override
    public String getGroupName() {
        return "GroupName";
    }

    @Nullable
    @Override
    public String getBuilderId() {
        return getClass().getName();
    }

    @Override
    public ModuleWizardStep modifyProjectTypeStep(@NotNull SettingsStep settingsStep) {
        return new EmptyStep();
    }

    @Override
    public ModuleType<?> getModuleType() {
        ModuleType moduleType = new ModuleType("MyModuleIdss") {
            @NotNull
            @Override
            public ModuleBuilder createModuleBuilder() {
                return MyModuleBuilder.this;
            }

            @Nls(capitalization = Nls.Capitalization.Title)
            @NotNull
            @Override
            public String getName() {
                return "NewModuleType";
            }

            @Nls(capitalization = Nls.Capitalization.Sentence)
            @NotNull
            @Override
            public String getDescription() {
                return "ModuleType";
            }

            @NotNull
            @Override
            public Icon getNodeIcon(boolean b) {
                return AllIcons.Actions.Refresh;
            }
        };
        return moduleType;
    }


    /**
     * @description: 配置步骤一
     *
     * @author: chenzhiwei
     * @create: 2020/5/31 11:47
     * @return com.intellij.ide.util.projectWizard.ModuleWizardStep 
     */
    @Nullable
    @Override
    public ModuleWizardStep getCustomOptionsStep(WizardContext context, Disposable parentDisposable) {
        return new MyModuleWizardStep1();
    }

    /**
     * @description: 配置步骤二
     *
     * @author: chenzhiwei
     * @create: 2020/5/31 11:48
     * @return com.intellij.ide.util.projectWizard.ModuleWizardStep[] 
     */
    @Override
    public ModuleWizardStep[] createWizardSteps(@NotNull WizardContext wizardContext, @NotNull ModulesProvider modulesProvider) {
        return new ModuleWizardStep[]{new MyModuleWizardStep2()};
    }

    /**
     * @description: 配置最后步骤
     *
     * @author: chenzhiwei
     * @create: 2020/5/31 11:48
     * @return com.intellij.ide.util.projectWizard.ModuleWizardStep 
     */
    @Nullable
    @Override
    public ModuleWizardStep modifySettingsStep(@NotNull SettingsStep settingsStep) {
        Condition<SdkTypeId> condition = sdkTypeId -> sdkTypeId == JavaSdk.getInstance();

        return  new MyModuleWizardStep3(settingsStep, this, condition);
    }

    /**
     * @description: finish完成回调函数
     *
     * @author: chenzhiwei
     * @create: 2020/5/31 11:48
     * @return void 
     */
    @Override
    public void setupRootModel(@NotNull ModifiableRootModel modifiableRootModel) {
        Messages.showInfoMessage("111", "22");
    }
}


7、plugin.xml配置
 <extensions defaultExtensionNs="com.intellij">
    <moduleBuilder builderClass="MyModuleBuilder" id="moduleIds"/>
  </extensions>



WriteCommandAction.wri

String cintent
VirtualFile pomfile=root.findOrCreateChildData(this,pom.xml)
VfsUtil.saveText(pomfile,content)
Document doc=FileDocumentManager.getInstance().getDocument(pomfile)
PsiDocumentManager.getInstance(project).doPostponedOperationAndUnblockDocument(doc)
FileDocumentManager.getinstance().reloadFromDisk(doc)

三十五:代码提示并修复
public class MyAbstractBaseJavaLocalInspectionTool2 extends AbstractBaseJavaLocalInspectionTool {

    @NotNull
    @Override
    public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {

        JavaElementVisitor visitor = new JavaElementVisitor() {
            @Override
            public void visitField(PsiField field) {
                super.visitField(field);
                holder.registerProblem(field, "hello world");
            }
        };
        return visitor;
    }

    @NotNull
    @Override
    public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) {
        SuppressQuickFix suppressQuickFix = new SuppressQuickFix() {
            @Nls(capitalization = Nls.Capitalization.Sentence)
            @NotNull
            @Override
            public String getFamilyName() {
                return "QuickFix2222";
            }

            @Override
            public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor problemDescriptor) {
                System.out.println("==========");
            }

            @Override
            public boolean isAvailable(@NotNull Project project, @NotNull PsiElement psiElement) {
                return psiElement instanceof PsiField;
            }

            @Override
            public boolean isSuppressAll() {
                return false;
            }
        };
        return new SuppressQuickFix[]{suppressQuickFix};

    }
    
}



<extensions defaultExtensionNs="com.intellij">
    <localInspection  language="JAVA"
                      displayName="Test field error11"
                      groupPath="Java"
                      groupBundle="messages.InspectionsBundle"
                      groupKey="group.names.probable.bugs"
                      enabledByDefault="true"
                      level="ERROR" implementationClass="MyAbstractBaseJavaLocalInspectionTool2"/>
  </extensions>

 三十六:添加到右键菜单

<action id="EditorBasics.EditorIllustrationAction"
        class="org.intellij.sdk.editor.EditorIllustrationAction"
        text="Editor Replace Text"
        description="Replaces selected text with 'Replacement'."
        icon="SdkIcons.Sdk_default_icon">
  <add-to-group group-id="EditorPopupMenu" anchor="first"/>
</action>

三十七:是否显示action

public class EditorIllustrationAction extends AnAction {
  @Override
  public void update(@NotNull final AnActionEvent e) {
    // Get required data keys
    final Project project = e.getProject();
    final Editor editor = e.getData(CommonDataKeys.EDITOR);
    
    // Set visibility only in case of existing project and editor and if a selection exists
    e.getPresentation().setEnabledAndVisible( project != null 
                                              && editor != null 
                                              && editor.getSelectionModel().hasSelection() );
  }
}

三十七:代码元素前添加图标操作RunLineMarkerContributor

public class MyRunLineMarkerContributor extends RunLineMarkerContributor {
    @Nullable
    @Override
    public Info getInfo(@NotNull PsiElement psiElement) {

        if (psiElement instanceof PsiMethod) {

            AnAction[] array = new AnAction[3];
            array[0] = new AnAction("11111") {
                @Override
                public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
                    Messages.showInfoMessage("1", "1");
                }
            };
            array[1] = new AnAction("22222") {
                @Override
                public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
                    Messages.showInfoMessage("2", "2");
                }
            };
            array[2] = new AnAction("333333") {
                @Override
                public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
                    Messages.showInfoMessage("3", "3");
                }
            };
            return new Info(AllIcons.RunConfigurations.TestState.Run, array, psiElement1 -> "hello");
        }
        return null;
    }
}

      <runLineMarkerContributor language="JAVA" 

plugin.xml配置
implementationClass="MyRunLineMarkerContributor"/>

三十八:自定义文件语言:Language

public class PfcLanguage extends Language {
public static final PfcLanguage INSTANCE = new PfcLanguage();
protected PfcLanguage() {
super("pfc");
}
}

public class PfcFile extends PsiFileBase {

public PfcFile(@NotNull FileViewProvider viewProvider) {
super(viewProvider, PfcLanguage.INSTANCE);
}

@NotNull
@Override
public FileType getFileType() {
return PfcLanguageFileType.INSTANCE;
}

@Override
public String toString() {
return "Pfc File";
}
}

public class PfcLanguageFileType extends LanguageFileType {
public static final PfcLanguageFileType INSTANCE = new PfcLanguageFileType();

protected PfcLanguageFileType() {
super(PfcLanguage.INSTANCE);
}

@NotNull
@Override
public String getName() {
return "Pfc file";
}

@NotNull
@Override
public String getDescription() {
return "pfc language file";
}

@NotNull
@Override
public String getDefaultExtension() {
return "pfc";
}

@Nullable
@Override
public Icon getIcon() {
// return PinganIcons.API_FILE;
return AllIcons.Actions.Back;
}
}




public class PfcFileTypeFactory extends FileTypeFactory {

@Override
public void createFileTypes(@NotNull FileTypeConsumer fileTypeConsumer) {
fileTypeConsumer.consume(PfcLanguageFileType.INSTANCE);
}
}



public class PfcParserDefinition implements ParserDefinition {

private static final IFileElementType PLANTUML_FILE_ELEMENT_TYPE = new IFileElementType(PfcLanguage.INSTANCE) {
@Override
public ASTNode parseContents(ASTNode chameleon) {
final CharSequence chars = chameleon.getChars();
return ASTFactory.leaf(PlainTextTokenTypes.PLAIN_TEXT, chars);
}
};

@NotNull
@Override
public Lexer createLexer(Project project) {
return new EmptyLexer();
}

@NotNull
@Override
public TokenSet getWhitespaceTokens() {
return TokenSet.EMPTY;
}

@NotNull
@Override
public TokenSet getCommentTokens() {
return TokenSet.EMPTY;
}

@NotNull
@Override
public TokenSet getStringLiteralElements() {
return TokenSet.EMPTY;
}

@NotNull
@Override
public PsiParser createParser(final Project project) {
throw new UnsupportedOperationException("Not supported1111");
}

@Override
public IFileElementType getFileNodeType() {
return PLANTUML_FILE_ELEMENT_TYPE;
}

@Override
public PsiFile createFile(FileViewProvider viewProvider) {
return new PfcFile(viewProvider);
}

@Override
public SpaceRequirements spaceExistenceTypeBetweenTokens(ASTNode left, ASTNode right) {
return SpaceRequirements.MAY;
}

@NotNull
@Override
public PsiElement createElement(ASTNode node) {
return PsiUtilCore.NULL_PSI_ELEMENT;
}
}

<fileTypeFactory implementation="com.pingan.core.language.pfc.PfcFileTypeFactory"/>
<lang.parserDefinition language="pfc" implementationClass="com.pingan.core.language.pfc.PfcParserDefinition"/>
三十九:自定义文件类型并添加图标执行

四十:添加到主界面的按钮:
<add-to-group group-id="NavBarToolBar"/>

四十一:plugin.xml引用外部xml配置
 <depends optional="true" config-file="plugin_xxx.xml">com.intellij.xxxx</depends>
 

四十二:ctrl+鼠标左键
XmlTagGotoDeclarationHandler implements GotoDeclarationHandler



    <gotoDeclarationHandler implementation="com.pingan.contributor.XmlTagGotoDeclarationHandler"/>

  

四十二:关键字补全:CompletionContributor

<completion.contributor language="PUML"
                                implementationClass="org.plantuml.idea.lang.PlantUmlCompletionContributor"/>

public class PfcCompletionContributor extends CompletionContributor implements DumbAware {
private static final Logger LOG = Logger.getInstance(PfcCompletionContributor.class);

public PfcCompletionContributor() {
extend(CompletionType.BASIC, PlatformPatterns.psiElement(), new PfcCompletionProvider(PfcLanguageDescriptor.INSTANCE.keywords));
extend(CompletionType.BASIC, PlatformPatterns.psiElement(), new PfcCompletionProvider(PfcLanguageDescriptor.INSTANCE.types));
extend(CompletionType.BASIC, PlatformPatterns.psiElement(), new PfcCompletionProvider(PfcLanguageDescriptor.INSTANCE.keywordsWithoutHighlight));
}

public void fillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull CompletionResultSet result) {
int offset = parameters.getOffset();
Document document = parameters.getEditor().getDocument();
int lineStartOffset = document.getLineStartOffset(document.getLineNumber(offset));
String text = document.getText(TextRange.create(lineStartOffset, offset));
Iterator iterator;
String value;
if (text.matches("\\s*!\\w*$")) {
iterator = PfcLanguageDescriptor.INSTANCE.preproc.iterator();
while (iterator.hasNext()) {
value = (String) iterator.next();
result.addElement(LookupElementBuilder.create(value.substring(1)).withPresentableText(value).withCaseSensitivity(true).bold());
}
} else if (text.matches("\\s*@\\w*$")) {
iterator = PfcLanguageDescriptor.INSTANCE.tags.iterator();

while (iterator.hasNext()) {
value = (String) iterator.next();
result.addElement(LookupElementBuilder.create(value.substring(1)).withPresentableText(value).withCaseSensitivity(true).bold());
}
} else {
if (text.endsWith("!")) {
return;
}

super.fillCompletionVariants(parameters, result);
// if (PlantUmlSettings.getInstance().isAutoComplete()) {
// WordCompletionContributor.addWordCompletionVariants(result, parameters, Collections.emptySet());
// }
WordCompletionContributor.addWordCompletionVariants(result, parameters, Collections.emptySet());
}
}

}


public class PfcCompletionProvider extends CompletionProvider<CompletionParameters> {

private final List<String> myItems;

PfcCompletionProvider(List<String> items) {
myItems = items;
}
@Override
protected void addCompletions(@NotNull CompletionParameters parameters, @NotNull ProcessingContext processingContext, @NotNull CompletionResultSet result) {
if (parameters.getInvocationCount() == 0) {
return;
}
for (String item : myItems) {
result.addElement(LookupElementBuilder.create(item).withCaseSensitivity(true).withItemTextItalic(true));
}
}
}


public enum PfcLanguageDescriptor {
INSTANCE;

public static final String IDEA_PARTIAL_RENDER = "idea.partialRender";
public static final String IDEA_DISABLE_SYNTAX_CHECK = "idea.disableSyntaxCheck";

public static final String TAGS = "uml|dot|jcckit|ditaa|salt|math|latex|mindmap|gantt|wbs";

public final List<String> types = Collections.unmodifiableList(Arrays.asList(
"actor",
"participant",
"usecase",
"class",
"interface",
"abstract",
"enum",
"component",
"state",
"object",
"artifact",
"folder",
"rectangle",
"node",
"frame",
"cloud",
"database",
"storage",
"agent",
"stack",
"boundary",
"control",
"entity",
"card",
"file",
"package",
"queue",
"archimate",
"diamond"

));
public final List<String> tags = Collections.unmodifiableList(Arrays.asList(
"@startuml",
"@startdot",
"@startjcckit",
"@startditaa",
"@startsalt",
"@startmath",
"@startlatex",
"@startmindmap",
"@startgantt",
"@startwbs",
"@enduml",
"@enddot",
"@endjcckit",
"@endditaa",
"@endsalt",
"@endmath",
"@endlatex",
"@endmindmap",
"@endgantt",
"@endwbs"

));

public final List<String> keywordsWithoutHighlight = Collections.unmodifiableList(Arrays.asList(
"as",
"also",
"of",
"on",
"is"
));

public final List<String> keywords = Collections.unmodifiableList(Arrays.asList(
"autonumber",
"caption",
"title",
"newpage",
"box",
"alt",
"else",
"opt",
"loop",
"par",
"break",
"critical",
"note",
"rnote",
"hnote",
"legend",
"group",
"left",
"right",
"link",
"over",
"end",
"activate",
"deactivate",
"destroy",
"create",
"footbox",
"hide",
"show",
"skinparam",
"skin",
"top",
"bottom",
"top to bottom direction",
"package",
"namespace",
"page",
"up",
"down",
"if",
"else",
"elseif",
"endif",
"partition",
"footer",
"header",
"center",
"rotate",
"ref",
"return",
"repeat",
"start",
"stop",
"while",
"endwhile",
"fork",
"again",
"kill",
"order",
"allow_mixing",
"allowmixing",
"mainframe"
));

public final List<String> pluginSettingsPattern = Collections.unmodifiableList(Arrays.asList(
IDEA_PARTIAL_RENDER,
IDEA_DISABLE_SYNTAX_CHECK
));



public final List<String> preproc = Collections.unmodifiableList(Arrays.asList(
"!exit",
"!include",
"!pragma",
"!define",
"!undef",
"!if",
"!ifdef",
"!endif",
"!ifndef",
"!else",
"!definelong",
"!enddefinelong"
));



}

  

四十三:选择文件夹

FileSaverDescriptor fsd = new FileSaverDescriptor("Save diagram", "Please choose where to save diagram");
        VirtualFile baseDir = ProjectUtil.guessProjectDir(anActionEvent.getProject());
        final VirtualFileWrapper wrapper = FileChooserFactory.getInstance().createSaveFileDialog(fsd, anActionEvent.getProject()).save(baseDir, "defaultFileName");
        

  

四十四:监听文件修改

1、实现DocumentListener接口

public class PfcDocumentListener implements DocumentListener {

    @Override
    public void documentChanged(@NotNull DocumentEvent event) {
        FileDocumentManager instance = FileDocumentManager.getInstance();
        VirtualFile file = instance.getFile(event.getDocument());
        EditorFactory editorFactory = EditorFactory.getInstance();
        Editor[] editors = editorFactory.getEditors(event.getDocument());
        System.out.println("=========");
    }
}


2、注册监听器
EditorEventMulticaster eventMulticaster = EditorFactory.getInstance().getEventMulticaster();
        eventMulticaster.addDocumentListener(plantUmlDocumentListener);
移除监听器
  EditorEventMulticaster eventMulticaster = EditorFactory.getInstance().getEventMulticaster();
        eventMulticaster.removeDocumentListener(plantUmlDocumentListener);

示例:
public class PlantUmlApplicationComponent implements ApplicationComponent {
    private DocumentListener plantUmlDocumentListener = new PfcDocumentListener();

    public PlantUmlApplicationComponent() {
		PlantUmlApplicationComponent.class.getClassLoader().setDefaultAssertionStatus(false);
	}

	@Override
    public void initComponent() {
        EditorEventMulticaster eventMulticaster = EditorFactory.getInstance().getEventMulticaster();
        eventMulticaster.addDocumentListener(plantUmlDocumentListener);
    }

    @Override
    public void disposeComponent() {
        EditorEventMulticaster eventMulticaster = EditorFactory.getInstance().getEventMulticaster();
        eventMulticaster.removeDocumentListener(plantUmlDocumentListener);
    }

    @Override
    @NotNull
    public String getComponentName() {
        return "PlantUmlApplicationComponent";
    }

}

  <application-components>
    <!-- Add your application components here -->
    <component>
      <implementation-class>com.pingan.core.PlantUmlApplicationComponent</implementation-class>
    </component>
  </application-components>

  

四十五:监听字符变化

1、实现CaretListener接口
public class PfcCaretListener implements CaretListener {

    @Override
    public void caretPositionChanged(@NotNull CaretEvent event) {
        System.out.println("========");
    }

    @Override
    public void caretAdded(@NotNull CaretEvent event) {
        System.out.println("=========");
    }
}

2、注册监听
public class PlantUmlApplicationComponent implements ApplicationComponent {
    private DocumentListener plantUmlDocumentListener = new PfcDocumentListener();
    private CaretListener pfcCaretListener = new PfcCaretListener();

    public PlantUmlApplicationComponent() {
		PlantUmlApplicationComponent.class.getClassLoader().setDefaultAssertionStatus(false);
	}

	@Override
    public void initComponent() {
        EditorEventMulticaster eventMulticaster = EditorFactory.getInstance().getEventMulticaster();
        eventMulticaster.addDocumentListener(plantUmlDocumentListener);
        eventMulticaster.addCaretListener(pfcCaretListener);
    }

    @Override
    public void disposeComponent() {
        EditorEventMulticaster eventMulticaster = EditorFactory.getInstance().getEventMulticaster();
        eventMulticaster.removeDocumentListener(plantUmlDocumentListener);
        eventMulticaster.removeCaretListener(pfcCaretListener);
    }

    @Override
    @NotNull
    public String getComponentName() {
        return "PlantUmlApplicationComponent";
    }

}

    <application-components>
      <!-- Add your application components here -->
      <component>
        <implementation-class>com.pingan.core.PlantUmlApplicationComponent</implementation-class>
      </component>
    </application-components>

  

四十六:添加鼠标事件

1、鼠标右键事件
        panel.addMouseListener(new PopupHandler() {
            @Override
            public void invokePopup(Component component, int x, int y) {
                ActionManager.getInstance().createActionPopupMenu("hello", new ActionGroup() {
                    @NotNull
                    @Override
                    public AnAction[] getChildren(@Nullable AnActionEvent anActionEvent) {
                        return new AnAction[]{new DownloadImageAction()};
                    }
                }).getComponent().show(component, x, y);
            }
        });

2、鼠标滚轮事件
addMouseWheelListener
imagePanel.addMouseWheelListener((wheelEvent) -> {
System.out.println(wheelEvent.getWheelRotation());
});

  

四十七:如果运行是报ClassNOtFoundException,考虑添加以下内容
  <depends>com.intellij.modules.java</depends>
  <depends>com.intellij.properties</depends>
  <depends>org.jetbrains.plugins.yaml</depends>
  <depends>org.jetbrains.kotlin</depends>

  

四十八:Tree使用SimpleTree

JTree tree = new SimpleTree();
DefaultTreeModel   model = (DefaultTreeModel) tree.getModel();
        DefaultTreeCellRenderer cellRenderer = (DefaultTreeCellRenderer) tree.getCellRenderer();
        cellRenderer.setLeafIcon(PinganIcons.TOOL_WINDOW);
        cellRenderer.setClosedIcon(PinganIcons.TOOL_WINDOW);
        cellRenderer.setOpenIcon(PinganIcons.TOOL_WINDOW);
        JBScrollPane scrollPane = new JBScrollPane(tree);
DefaultMutableTreeNode rootTreeNode = new DefaultMutableTreeNode(rootNode);
        model.setRoot(rootTreeNode);
// 设置图标
tree.setCellRenderer(new ColoredTreeCellRenderer() {
@Override
public void customizeCellRenderer(@NotNull JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
if (tree instanceof SimpleTree) {
setIcon(PinganIcons.TOOL_WINDOW);
append(String.valueOf(value));
}
}
});

  

四十九:修改过的文件
ChangeListManager changeListManager = ChangeListManager.getInstance(project);

五十:plugin.xml添加图标方式:使用相对路劲引入

五十一:多个窗口共用一个window时,不能将组件进行单例化,否则多个项目面板会错乱



有志之士,共同学习
原文地址:https://www.cnblogs.com/antlord/p/12863323.html