gitee地址:https://gitee.com/jyq_18792721831/studyplugin.git
idea插件开发入门idea插件开发–配置idea插件开发–服务-翻译插件idea插件开发–组件–编程久坐提醒
idea插件开发--配置
介绍
很多时候,我们使用插件都需要配置一些信息,只有配置了信息,插件才能更好的进行服务,增加我们的效率。
但是又不能每次使用插件都进行配置,即使我们使用对象将配置缓存下来,但是当idea重启后,又必须重新进行配置,这样的插件是没人使用的。
所以我们需要将配置进行持久化,当idea进行重启后,也能度过读取持久化的配置,再次提供服务。
idea插件提供的持久化方案有多种,这只是最简单,最基础的一种。
即使是最简单,最基础的这种,也能满足绝大多数的配置持久化需求。
存储接口
PropertiesComponent
公有三个子类
首先PropertiesComponentImpl
实现了配置的存储和读取。
然后AppPropertiesComponentImpl
则是全局的,所有的idea实例只有一份相同的配置的实现,即AppPropertiesComponentImpl
的作用域是对全部的idea生效。所有的idea实例,只要key相同,则值也是相同的。
而ProjectPropertiesComponentImpl
的作用域则是对项目进行隔离,每个idea实例都可以有相同的key,而且对应值可以不同。
具体使用哪一种作用域,则是在编码时的getInstance
方法决定,getInstance
方法是个重载方法,一个有参数,参数是Project
,一个没有参数。
很明显,没有参数的就是全局的,作用域是App,有参数的是就是部分的,作用域是Project。
配置界面
插件的配置一般是setting的界面中配置的
要想自己的插件也在这里配置,就必须自己决定配置的界面,以及告诉idea,如何展示。
SearchableConfigurable
接口。
实现了SearchableConfigurable
接口,就会在settings下面的tools下面展示。
SearchableConfigurable
定义了一些方法:
- getId:获取id,插件内不能重复
- getDisplayName:获取tools下面展示的名字
- createComponent:获取展示的界面
- isModified:是否可用,是否可配置
- apply:配置完成后,点击了确定或者应用后执行的逻辑
实例
目标
配置一个测试的值,然后使用Action触发读取,并使用通知展示。
创建项目
一定要创建项目,因为当一个项目中存在多个模块,且多个模块都是插件的时候,就存在无法直接启动和调试的问题。
国内开发插件是有点难受,使用gradle的方式吧,依赖好管理,但是idea的sdk实在下载不下来,而且,gradler管理工具也不咋会用。
算了,还是老老实实的用最原始的方式,也是最靠谱的方式。
创建好后,配置plugin.xml
(其实就是将helloword的plugin.xml
拷贝过来,修改id和name即可,helloword见idea插件开发入门)
<extensions defaultExtensionNs="com.intellij">
<!-- Add your extensions here -->
<!-- displayType只有这四种类型, id 在一个插件内不能重复,isLogByDefault表示是否在 Event Log 中记录 -->
<notificationGroup displayType="BALLOON" id="helloword.notification.balloon" isLogByDefault="false"/>
</extensions>
<actions>
<!-- Add your actions here -->
<action id="com.study.plugin.simpleconfig" class="com.study.plugin.simpleconfig.action.TestConfigAction" text="TestConfigAction"
description="TestConfigAction">
<add-to-group group-id="ToolsMenu" anchor="last"/>
<keyboard-shortcut keymap="$default" first-keystroke="ctrl alt SEMICOLON"/>
</action>
</actions>
项目结构如图
工具类封装
NotificationUtil
封装三种类型的通知
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationGroup;
import com.intellij.notification.NotificationGroupManager;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
public class NotificationUtil {
// 获取通知组管理器
private static NotificationGroupManager manager = NotificationGroupManager.getInstance();
// 获取注册的通知组
private static NotificationGroup balloon = manager.getNotificationGroup("helloword.notification.balloon");
public static void info(String msg) {
Notification notification = balloon.createNotification(msg, NotificationType.INFORMATION);
Notifications.Bus.notify(notification);
}
public static void warning(String msg) {
Notification notification = balloon.createNotification(msg, NotificationType.WARNING);
Notifications.Bus.notify(notification);
}
public static void error(String msg) {
Notification notification = balloon.createNotification(msg, NotificationType.ERROR);
Notifications.Bus.notify(notification);
}
}
接着把插件的id,name等等的常量做个封装
public class SimpleConfigKeys {
public static final String SETTING_ID = "com.study.plugin.simpleconfig.setting.id";
public static final String SETTING_NAME = "简单配置测试";
public static final String SETTING_TEST_CONFIG_KEY = "text.config";
}
还有最重要的一个,配置值的存储工具类
import com.intellij.ide.util.PropertiesComponent;
public class SimpleConfigUtil {
private static final PropertiesComponent propertiesComponent = PropertiesComponent.getInstance();
public static String getString(String key) {
// key
// key defaultValue
return propertiesComponent.getValue(key);
}
public static void save(String key, Object value) {
if (value instanceof String) {
save(key, (String) value);
} else if (value instanceof Integer) {
save(key, (int) value);
} else if (value instanceof Boolean) {
save(key, (boolean) value);
} else if (value instanceof Float) {
save(key, (float) value);
} else {
NotificationUtil.error("type error : " + value);
}
}
private static void save(String key, String value) {
// key value
propertiesComponent.setValue(key, value);
}
private static void save(String key, int value) {
// key value defaultValue
propertiesComponent.setValue(key, value, 0);
}
private static void save(String key, boolean value) {
// key value
// key value defaultValue
propertiesComponent.setValue(key, value);
}
private static void save(String key, float value) {
// key value defaultValue
propertiesComponent.setValue(key, value, 0.0f);
}
}
配置存储全局作用域即可。
setting界面
创建UI
增加后,会生成java类和form文件
界面结构如下,需要什么,可以拖动控件放到需要的位置上
最顶层是一个JPanel,属性名字是rootPanel
为了方便管理,我们增加一个二级Pannel,不需要名字,增加边框
选中Panel,并设置border的属性即可
二级Panel下有两个控件:JLabel,用于展示,JTextField,用于输入。
因为我们需要获取输入的值,所以需要给JTextField设置名字。
此时查看java类,是没有代码生成的,我们需要idea帮我们将form转为java代码
然后设置module的启动配置
有了启动配置后,进行编译,编译成功后,java类中就会自动生成代码
前面说过,我们需要获取输入框的控件,然后获取输入的值,设置动作监听等等,所以使用lombok将JTextField控件暴露出去
将lombok加入到classpath中(lombok在高版本的idea中自动支持)
加入后会下载相关的jar,有可能会非常慢
需要注意,rootJPanel也需要增加getter方法
虽然自动生成了getRootComponent方法,但是这个方法不是给我们编码用的
注释的很明白,不要在你的代码中使用这些方法
在java文件中,右键,自动生成测试方法
一定要给最顶层的JPanel设置属性名字,才能自动生成测试方法
你的UI就会展示出来
如果还设置了动作监听,也能进行测试的,按钮什么的,都可以进行测试。
配置界面到setting中
写好了界面,我们就需要把界面配置到setting中,也就是需要编写实现SearchableConfigurable
的类了
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.util.NlsContexts;
import com.study.plugin.simpleconfig.ui.SimpleConfigSettingUI;
import com.study.plugin.simpleconfig.util.NotificationUtil;
import com.study.plugin.simpleconfig.util.SimpleConfigKeys;
import com.study.plugin.simpleconfig.util.SimpleConfigUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.JComponent;
import javax.swing.JTextField;
public class SimpleConfigSetting implements SearchableConfigurable {
private SimpleConfigSettingUI form = new SimpleConfigSettingUI();
@Override
public @NotNull
@NonNls
String getId() {
return SimpleConfigKeys.SETTING_ID;
}
@Override
public @NlsContexts.ConfigurableName String getDisplayName() {
return SimpleConfigKeys.SETTING_NAME;
}
@Override
public @Nullable
JComponent createComponent() {
return form.$$$getRootComponent$$$();
}
@Override
public boolean isModified() {
return true;
}
@Override
public void apply() throws ConfigurationException {
JTextField simpleConfigInput = form.getSimpleConfigInput();
String inputValue = simpleConfigInput.getText();
SimpleConfigUtil.save(SimpleConfigKeys.SETTING_TEST_CONFIG_KEY, inputValue);
NotificationUtil.info("save " + inputValue + " success!");
}
}
其实很简单,就是把输入框中的值,保存到持久化中。
编写完成后,需要将我们编写的类配置到idea中。
可以把整个idea想象成一个spring的项目,在spring中,是spring去管理对象实例的,在idea中,也类似差不多。在spring中有注解和xml方式注入bean,在idea中主要是在plugin.xml
中将我们自己写的实例注入到idea中的。
所以需要将SearchableConfigurable
接口的实现类的实例,注入到idea中
<extensions defaultExtensionNs="com.intellij">
<!-- Add your extensions here -->
<!-- displayType只有这四种类型, id 在一个插件内不能重复,isLogByDefault表示是否在 Event Log 中记录 -->
<notificationGroup displayType="BALLOON" id="simpleconfig.notification.balloon" isLogByDefault="false"/>
<applicationConfigurable parentId="tools" instance="com.study.plugin.simpleconfig.config.SimpleConfigSetting"
id="com.study.plugin.simpleconfig.setting.config.id" displayName="测试配置菜单"/>
</extensions>
可以看到我们注入的是全局的配置,如果是项目的配置,就需要使用projectConfigurable
的标签了,这里面配置的类都是configurable
接口的实现类。
读取配置
读取配置是在Action中的,也很简单,从持久化工具类中获取值,然后通知输出即可
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.study.plugin.simpleconfig.util.NotificationUtil;
import com.study.plugin.simpleconfig.util.SimpleConfigKeys;
import com.study.plugin.simpleconfig.util.SimpleConfigUtil;
public class TestConfigAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
String configValue = SimpleConfigUtil.getString(SimpleConfigKeys.SETTING_TEST_CONFIG_KEY);
if(StringUtil.isEmpty(configValue)) {
NotificationUtil.error("empty");
}
NotificationUtil.info(configValue);
}
}
验证
至此,整个实例就完成了,完整的项目结构如下
启动测试下(注意启动正确的module)
首先是setting的配置页
可以看到,这里配置的就是我们在plugin.xml
中配置的数据生效了。
接下来是配置界面
也是一样的,我们试着配置
然后使用tools下的菜单触发
因为我们使用的是唯一的沙盒,所有会有helloword的插件。
点击,发现和预期的一样,通知里面是我们配置的值。
接下来重启idea(沙盒的)
可以看到,重启沙盒的idea后,原本开发的idea的调试关联就丢失了
在非调试的状态下,重新触发读取操作,发现还是能够读取到我们配置的值,即使我们重启过idea(沙盒)
这样就达到了我们的目的。
扩展
如果我想每次配置的时候,都把已有的配置放在输入框中呢?
因为现在打开配置,默认是空的,这样如果打开配置,直接点击确定,会把空值写入。
要实现这个小功能,也很简单,在获取配置的JPanel的之前,将配置中的值,设置到控件中即可。
还记得吗,我们之前配置的值是“测试1”,现在打开配置界面,看看输入框中是不是
预期一致。
打包
打包后会生成可安装的压缩包
和helloword中的不同,helloword中的是jar包,这里是zip包。
打包后生成jar包还是zip包,取决于是否有第三方依赖。
在simpleconfig中,我们有lombok的第三方依赖,在打包的时候,会把lombok的包也打进去,所以是zip包,在helloword中,没有第三方包,所以是jar包。